diff --git a/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py index c69cb6c4dbb..f92fac32110 100644 --- a/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/charzero_drinfeld_module.py @@ -24,9 +24,13 @@ from .drinfeld_module import DrinfeldModule +from sage.functions.other import ceil from sage.rings.integer_ring import ZZ from sage.rings.infinity import Infinity +from sage.matrix.constructor import matrix +from sage.modules.free_module_element import vector + from sage.misc.cachefunc import cached_method from sage.misc.lazy_import import lazy_import @@ -444,3 +448,182 @@ def goss_polynomial(self, n, var='X'): X = poly_ring.gen() q = self._Fq.cardinality() return self._compute_goss_polynomial(n, q, poly_ring, X) + + +class DrinfeldModule_rational(DrinfeldModule_charzero): + """ + A class for Drinfeld modules defined over the fraction + field of the underlying function field + """ + def _phiT_matrix(self, polynomial_part): + r""" + Return the matrix of `\phi_T` modulo `\pi^s` where `s` is + chosen such that `\pi^s` is in the domain of convergence + of the logarithm. + + It is an helper function; do not call it directly. + """ + A = self.function_ring() + Fq = A.base_ring() + q = Fq.cardinality() + r = self.rank() + + gs = [] + for g in self.coefficients(sparse=False): + g = g.backend(force=True) + if g.denominator().is_one(): + gs.append(A(g.numerator().list())) + else: + raise ValueError("the Drinfeld module must have polynomial coefficients") + s = max(ceil(gs[i].degree() / (q**i - 1)) for i in range(1, r+1)) - 1 + if s < 0: + s = 0 + + M = matrix(Fq, s) + if polynomial_part: + P = vector(A, s) + qk = 1 + for k in range(r+1): + for i in range(s): + e = (i+1)*qk + if polynomial_part: + P[i] += gs[k] >> e + for j in range(s): + e -= 1 + if e < 0: + break + M[i, j] += gs[k][e] + qk *= q + + if polynomial_part: + return M, P + else: + return M + + def class_polynomial(self): + r""" + Return the class polynomial, that is the Fitting ideal + of the class module, of this Drinfeld module. + + EXAMPLES: + + We check that the class module of the Carlitz module + is trivial:: + + sage: q = 5 + sage: Fq = GF(q) + sage: A = Fq['T'] + sage: K. = Frac(A) + sage: C = DrinfeldModule(A, [T, 1]); C + Drinfeld module defined by T |--> t + T + sage: C.class_polynomial() + 1 + + When the coefficients of the Drinfeld module have small + enough degrees, the class module is always trivial:: + + sage: r = 4 + sage: phi = DrinfeldModule(A, [T] + [A.random_element(degree=q**i) for i in range(1, r+1)]) + sage: phi.class_polynomial() + 1 + + Here is an example with a nontrivial class module:: + + sage: phi = DrinfeldModule(A, [T, -T^(2*q-1) + 2*T^(q-1)]) + sage: phi.class_polynomial() + T + 3 + """ + A = self.function_ring() + Fq = A.base_ring() + M = self._phiT_matrix(False) + s = M.nrows() + if s == 0: + # self is small + return A.one() + + v = vector(Fq, s) + v[s-1] = 1 + vs = [v] + for i in range(s-1): + v = v*M + vs.append(v) + V = matrix(vs) + V.echelonize() + + dim = V.rank() + pivots = V.pivots() + j = ip = 0 + for i in range(dim, s): + while ip < dim and j == pivots[ip]: + j += 1 + ip += 1 + V[i,j] = 1 + + N = (V * M * ~V).submatrix(dim, dim) + return A(N.charpoly()) + + def taelman_exponential_unit(self): + r""" + Return the exponential of the fundamental Taelman unit. + + EXAMPLES: + + The Taelman exponential unit of The Carlitz module is `1`:: + + sage: q = 7 + sage: Fq = GF(q) + sage: A = Fq['T'] + sage: K. = Frac(A) + sage: C = DrinfeldModule(A, [T, 1]); C + Drinfeld module defined by T |--> t + T + sage: C.taelman_exponential_unit() + 1 + + The same occurs more generally when the coefficients of the + Drinfeld module have small enough degrees:: + + sage: r = 4 + sage: phi = DrinfeldModule(A, [T] + [A.random_element(degree=q**i) for i in range(1, r+1)]) + sage: phi.taelman_exponential_unit() + 1 + + Usually, as soon as we leave the world of small Drinfeld modules, + Taelman's exponential units are highly non trivial:: + + sage: phi = DrinfeldModule(A, [T, T^(2*q+1), T^3]) + sage: phi.taelman_exponential_unit() + T^52 + T^22 + T^8 + T^2 + 1 + """ + A = self.function_ring() + Fq = A.base_ring() + q = Fq.cardinality() + M, P = self._phiT_matrix(True) + s = M.nrows() + if s == 0: + # self is small + return A(1) + + gs = self.coefficients(sparse=False) + v = vector(Fq, s) + v[s-1] = 1 + p = A.zero() + vs = [v] + ps = [p] + for i in range(s): + pq = p + p = v * P + for j in range(len(gs) - 1): + p += gs[j] * pq + pq = pq ** q + p += gs[-1] * pq + v = v * M + vs.append(v) + ps.append(p) + vs.reverse() + ps.reverse() + V = matrix(vs) + + unit = V.left_kernel().basis()[0] + expunit = sum(unit[i]*ps[i] for i in range(s+1)) + expunit /= expunit.numerator().leading_coefficient() + return expunit diff --git a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py index 0b8d4cd32ff..f65b6753831 100644 --- a/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py +++ b/src/sage/rings/function_field/drinfeld_modules/drinfeld_module.py @@ -37,6 +37,7 @@ from sage.misc.misc_c import prod from sage.rings.integer import Integer from sage.rings.integer_ring import ZZ +from sage.rings.fraction_field import FractionField_generic from sage.rings.polynomial.ore_polynomial_element import OrePolynomial from sage.rings.polynomial.polynomial_ring import PolynomialRing_generic from sage.structure.parent import Parent @@ -621,9 +622,17 @@ def __classcall_private__(cls, function_ring, gen, name='t'): raise ValueError('generator must have positive degree') # Instantiate the appropriate class: - if base_field.is_finite(): + backend = base_field.backend(force=True) + if backend.is_finite(): from sage.rings.function_field.drinfeld_modules.finite_drinfeld_module import DrinfeldModule_finite return DrinfeldModule_finite(gen, category) + if isinstance(backend, FractionField_generic): + ring = backend.ring() + if (isinstance(ring, PolynomialRing_generic) + and ring.base_ring() is function_ring_base + and base_morphism(T) == ring.gen()): + from .charzero_drinfeld_module import DrinfeldModule_rational + return DrinfeldModule_rational(gen, category) if not category._characteristic: from .charzero_drinfeld_module import DrinfeldModule_charzero return DrinfeldModule_charzero(gen, category) diff --git a/src/sage/rings/ring_extension_element.pyx b/src/sage/rings/ring_extension_element.pyx index 600b1d1a62e..d74ed04ac26 100644 --- a/src/sage/rings/ring_extension_element.pyx +++ b/src/sage/rings/ring_extension_element.pyx @@ -129,6 +129,46 @@ cdef class RingExtensionElement(CommutativeAlgebraElement): wrapper.__doc__ = method.__doc__ return wrapper + def __getitem__(self, i): + r""" + Return the `i`-th item of this element. + + This methods calls the appropriate method of the backend if + ``import_methods`` is set to ``True`` + + EXAMPLES:: + + sage: R. = QQ[] + sage: E = R.over() + sage: P = E(x^2 + 2*x + 3) + sage: P[0] + 3 + """ + if (self._parent)._import_methods: + output = self._backend[to_backend(i)] + return from_backend(output, self._parent) + return TypeError("this element is not subscriptable") + + def __call__(self, *args, **kwargs): + r""" + Call this element. + + This methods calls the appropriate method of the backend if + ``import_methods`` is set to ``True`` + + EXAMPLES:: + + sage: R. = QQ[] + sage: E = R.over() + sage: P = E(x^2 + 2*x + 3) + sage: P(1) + 6 + """ + if (self._parent)._import_methods: + output = self._backend(*to_backend(args), **to_backend(kwargs)) + return from_backend(output, self._parent) + return TypeError("this element is not callable") + def __dir__(self): """ Return the list of all the attributes of this element;