Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
""" Laurent Series Rings
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.base_ring() Rational Field sage: S = LaurentSeriesRing(GF(17)['x'], 'y') sage: S Laurent Series Ring in y over Univariate Polynomial Ring in x over Finite Field of size 17 sage: S.base_ring() Univariate Polynomial Ring in x over Finite Field of size 17
.. SEEALSO::
* :func:`sage.misc.defaults.set_series_precision` """ #***************************************************************************** # Copyright (C) 2006 William Stein <wstein@gmail.com> # 2007 Robert Bradshaw <robertwb@math.washington.edu> # 2012 David Roe <roed.math@gmail.com> # 2014 Peter Bruin <P.J.Bruin@math.leidenuniv.nl> # 2017 Vincent Delecroix <20100.delecroix@gmail.com> # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #*****************************************************************************
from __future__ import print_function, absolute_import
from sage.categories.rings import Rings from sage.categories.integral_domains import IntegralDomains from sage.categories.fields import Fields from sage.categories.complete_discrete_valuation import CompleteDiscreteValuationFields
from .laurent_series_ring_element import LaurentSeries from . import polynomial from .ring import CommutativeRing
from sage.structure.unique_representation import UniqueRepresentation from sage.misc.cachefunc import cached_method
def is_LaurentSeriesRing(x): """ Return ``True`` if this is a *univariate* Laurent series ring.
This is in keeping with the behavior of ``is_PolynomialRing`` versus ``is_MPolynomialRing``.
TESTS::
sage: from sage.rings.laurent_series_ring import is_LaurentSeriesRing sage: K.<q> = LaurentSeriesRing(QQ) sage: is_LaurentSeriesRing(K) True """
class LaurentSeriesRing(UniqueRepresentation, CommutativeRing): r""" Univariate Laurent Series Ring.
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, 'x'); R Laurent Series Ring in x over Rational Field sage: x = R.0 sage: g = 1 - x + x^2 - x^4 +O(x^8); g 1 - x + x^2 - x^4 + O(x^8) sage: g = 10*x^(-3) + 2006 - 19*x + x^2 - x^4 +O(x^8); g 10*x^-3 + 2006 - 19*x + x^2 - x^4 + O(x^8)
You can also use more mathematical notation when the base is a field::
sage: Frac(QQ[['x']]) Laurent Series Ring in x over Rational Field sage: Frac(GF(5)['y']) Fraction Field of Univariate Polynomial Ring in y over Finite Field of size 5
Here the fraction field is not just the Laurent series ring, so you can't use the ``Frac`` notation to make the Laurent series ring::
sage: Frac(ZZ[['t']]) Fraction Field of Power Series Ring in t over Integer Ring
Laurent series rings are determined by their variable and the base ring, and are globally unique::
sage: K = Qp(5, prec = 5) sage: L = Qp(5, prec = 200) sage: R.<x> = LaurentSeriesRing(K) sage: S.<y> = LaurentSeriesRing(L) sage: R is S False sage: T.<y> = LaurentSeriesRing(Qp(5,prec=200)) sage: S is T True sage: W.<y> = LaurentSeriesRing(Qp(5,prec=199)) sage: W is T False
sage: K = LaurentSeriesRing(CC, 'q') sage: K Laurent Series Ring in q over Complex Field with 53 bits of precision sage: loads(K.dumps()) == K True sage: P = QQ[['x']] sage: F = Frac(P) sage: TestSuite(F).run()
When the base ring `k` is a field, the ring `k((x))` is a CDVF, that is a field equipped with a discrete valuation for which it is complete. The appropriate (sub)category is automatically set in this case::
sage: k = GF(11) sage: R.<x> = k[[]] sage: F = Frac(R) sage: F.category() Category of infinite complete discrete valuation fields sage: TestSuite(F).run()
TESTS:
Check if changing global series precision does it right (and that :trac:`17955` is fixed)::
sage: set_series_precision(3) sage: R.<x> = LaurentSeriesRing(ZZ) sage: 1/(1 - 2*x) 1 + 2*x + 4*x^2 + O(x^3) sage: set_series_precision(5) sage: R.<x> = LaurentSeriesRing(ZZ) sage: 1/(1 - 2*x) 1 + 2*x + 4*x^2 + 8*x^3 + 16*x^4 + O(x^5) sage: set_series_precision(20)
Check categories (:trac:`24420`)::
sage: LaurentSeriesRing(ZZ, 'x').category() Category of infinite integral domains sage: LaurentSeriesRing(QQ, 'x').category() Category of infinite complete discrete valuation fields sage: LaurentSeriesRing(Zmod(4), 'x').category() Category of infinite commutative rings
Check coercions (:trac:`24431`)::
sage: pts = [LaurentSeriesRing, ....: PolynomialRing, ....: PowerSeriesRing, ....: LaurentPolynomialRing] sage: LS = LaurentSeriesRing(QQ, 'x') sage: LSx = LS.gen()
sage: for P in pts: ....: x = P(QQ, 'x').gen() ....: assert parent(LSx * x) is LS, "wrong parent for {}".format(P)
sage: for P in pts: ....: y = P(QQ, 'y').gen() ....: try: ....: LSx * y ....: except TypeError: ....: pass ....: else: ....: print("wrong coercion {}".format(P)) """ Element = LaurentSeries
@staticmethod def __classcall__(cls, *args, **kwds): r""" TESTS::
sage: L = LaurentSeriesRing(QQ, 'q') sage: L is LaurentSeriesRing(QQ, name='q') True sage: loads(dumps(L)) is L True
sage: L.variable_names() ('q',) sage: L.variable_name() 'q' """
else:
def __init__(self, power_series): """ Initialization
EXAMPLES::
sage: K.<q> = LaurentSeriesRing(QQ, default_prec=4); K Laurent Series Ring in q over Rational Field sage: 1 / (q-q^2) q^-1 + 1 + q + q^2 + O(q^3)
sage: RZZ = LaurentSeriesRing(ZZ, 't') sage: RZZ.category() Category of infinite integral domains sage: TestSuite(RZZ).run()
sage: R1 = LaurentSeriesRing(Zmod(1), 't') sage: R1.category() Category of finite commutative rings sage: TestSuite(R1).run()
sage: R2 = LaurentSeriesRing(Zmod(2), 't') sage: R2.category() Category of infinite complete discrete valuation fields sage: TestSuite(R2).run()
sage: R4 = LaurentSeriesRing(Zmod(4), 't') sage: R4.category() Category of infinite commutative rings sage: TestSuite(R4).run()
sage: RQQ = LaurentSeriesRing(QQ, 't') sage: RQQ.category() Category of infinite complete discrete valuation fields sage: TestSuite(RQQ).run() """ else: raise ValueError('unrecognized base ring')
else:
names=power_series.variable_names(), category=category)
def base_extend(self, R): """ Return the Laurent series ring over R in the same variable as self, assuming there is a canonical coerce map from the base ring of self to R.
EXAMPLES::
sage: K.<x> = LaurentSeriesRing(QQ, default_prec=4) sage: K.base_extend(QQ['t']) Laurent Series Ring in x over Univariate Polynomial Ring in t over Rational Field """ else: raise TypeError("no valid base extension defined")
def fraction_field(self): r""" Return the fraction field of this ring of Laurent series.
If the base ring is a field, then Laurent series are already a field. If the base ring is a domain, then the Laurent series over its fraction field is returned. Otherwise, raise a ``ValueError``.
EXAMPLES::
sage: R = LaurentSeriesRing(ZZ, 't', 30).fraction_field() sage: R Laurent Series Ring in t over Rational Field sage: R.default_prec() 30
sage: LaurentSeriesRing(Zmod(4), 't').fraction_field() Traceback (most recent call last): ... ValueError: must be an integral domain """ self.variable_names(), self.default_prec()) else:
def change_ring(self, R): """ EXAMPLES::
sage: K.<x> = LaurentSeriesRing(QQ, default_prec=4) sage: R = K.change_ring(ZZ); R Laurent Series Ring in x over Integer Ring sage: R.default_prec() 4 """ default_prec=self.default_prec(), sparse=self.is_sparse())
def is_sparse(self): """ Return if ``self`` is a sparse implementation.
EXAMPLES::
sage: K.<x> = LaurentSeriesRing(QQ, sparse=True) sage: K.is_sparse() True """
def is_field(self, proof=True): """ A Laurent series ring is a field if and only if the base ring is a field.
TESTS::
sage: LaurentSeriesRing(QQ,'t').is_field() True sage: LaurentSeriesRing(ZZ,'t').is_field() False """
def is_dense(self): """ EXAMPLES::
sage: K.<x> = LaurentSeriesRing(QQ, sparse=True) sage: K.is_dense() False """
def _repr_(self): """ EXAMPLES::
sage: LaurentSeriesRing(QQ,'q') # indirect doctest Laurent Series Ring in q over Rational Field sage: LaurentSeriesRing(ZZ,'t',sparse=True) Sparse Laurent Series Ring in t over Integer Ring """
def _element_constructor_(self, x, n=0): r""" Construct a Laurent series from `x`.
INPUT:
- ``x`` -- object that can be converted into a Laurent series
- ``n`` -- (default: 0) multiply the result by `t^n`
EXAMPLES::
sage: R.<u> = LaurentSeriesRing(Qp(5, 10)) sage: S.<t> = LaurentSeriesRing(RationalField()) sage: R(t + t^2 + O(t^3)) (1 + O(5^10))*u + (1 + O(5^10))*u^2 + O(u^3)
Note that coercing an element into its own parent just produces that element again (since Laurent series are immutable)::
sage: u is R(u) True
Rational functions are accepted::
sage: I = sqrt(-1) sage: K.<I> = QQ[I] sage: P.<t> = PolynomialRing(K) sage: L.<u> = LaurentSeriesRing(QQ[I]) sage: L((t*I)/(t^3+I*2*t)) 1/2 + 1/4*I*u^2 - 1/8*u^4 - 1/16*I*u^6 + 1/32*u^8 + 1/64*I*u^10 - 1/128*u^12 - 1/256*I*u^14 + 1/512*u^16 + 1/1024*I*u^18 + O(u^20)
::
sage: L(t*I) / L(t^3+I*2*t) 1/2 + 1/4*I*u^2 - 1/8*u^4 - 1/16*I*u^6 + 1/32*u^8 + 1/64*I*u^10 - 1/128*u^12 - 1/256*I*u^14 + 1/512*u^16 + 1/1024*I*u^18 + O(u^20)
TESTS:
When converting from `R((z))` to `R((z))((w))`, the variable `z` is sent to `z` rather than to `w` (see :trac:`7085`)::
sage: A.<z> = LaurentSeriesRing(QQ) sage: B.<w> = LaurentSeriesRing(A) sage: B(z) z sage: z/w z*w^-1
Various conversions from PARI (see also :trac:`2508`)::
sage: L.<q> = LaurentSeriesRing(QQ) sage: L.set_default_prec(10) doctest:...: DeprecationWarning: This method is deprecated. See http://trac.sagemath.org/16201 for details. sage: L(pari('1/x')) q^-1 sage: L(pari('polchebyshev(5)')) 5*q - 20*q^3 + 16*q^5 sage: L(pari('polchebyshev(5) - 1/x^4')) -q^-4 + 5*q - 20*q^3 + 16*q^5 sage: L(pari('1/polchebyshev(5)')) 1/5*q^-1 + 4/5*q + 64/25*q^3 + 192/25*q^5 + 2816/125*q^7 + O(q^9) sage: L(pari('polchebyshev(5) + O(x^40)')) 5*q - 20*q^3 + 16*q^5 + O(q^40) sage: L(pari('polchebyshev(5) - 1/x^4 + O(x^40)')) -q^-4 + 5*q - 20*q^3 + 16*q^5 + O(q^40) sage: L(pari('1/polchebyshev(5) + O(x^10)')) 1/5*q^-1 + 4/5*q + 64/25*q^3 + 192/25*q^5 + 2816/125*q^7 + 8192/125*q^9 + O(q^10) sage: L(pari('1/polchebyshev(5) + O(x^10)'), -10) # Multiply by q^-10 1/5*q^-11 + 4/5*q^-9 + 64/25*q^-7 + 192/25*q^-5 + 2816/125*q^-3 + 8192/125*q^-1 + O(1) sage: L(pari('O(x^-10)')) O(q^-10) """
return x # ok, since Laurent series are immutable (no need to make a copy) # Convert x into a power series; if P is itself a Laurent # series ring A((t)), this prevents the implementation of # LaurentSeries.__init__() from effectively applying the # ring homomorphism A((t)) -> A((t))((u)) sending t to u # instead of the one sending t to t. We cannot easily # tell LaurentSeries.__init__() to be more strict, because # A((t)) -> B((u)) is expected to send t to u if A admits # a coercion to B but A((t)) does not, and this condition # would be inefficient to check there. self(self.polynomial_ring()(x.denominator())) else: # General case, pretend to be a polynomial and (x.base_ring() is self.base_ring() or x.base_ring() == self.base_ring()) and (is_Polynomial(x.numerator()) or is_MPolynomial(x.numerator())) ):
def construction(self): r""" Return the functorial construction of this Laurent power series ring.
The construction is given as the completion of the Laurent polynomials.
EXAMPLES::
sage: L.<t> = LaurentSeriesRing(ZZ, default_prec=42) sage: phi, arg = L.construction() sage: phi Completion[t, prec=42] sage: arg Univariate Laurent Polynomial Ring in t over Integer Ring sage: phi(arg) is L True
Because of this construction, pushout is automatically available::
sage: 1/2 * t 1/2*t sage: parent(1/2 * t) Laurent Series Ring in t over Rational Field
sage: QQbar.gen() * t I*t sage: parent(QQbar.gen() * t) Laurent Series Ring in t over Algebraic Field """
def _coerce_map_from_(self, P): """ Return a coercion map from `P` to ``self``, or True, or None.
The following rings admit a coercion map to the Laurent series ring `A((t))`:
- any ring that admits a coercion map to `A` (including `A` itself);
- any Laurent series ring, power series ring or polynomial ring in the variable `t` over a ring admitting a coercion map to `A`.
EXAMPLES::
sage: S.<t> = LaurentSeriesRing(ZZ) sage: S.has_coerce_map_from(ZZ) True sage: S.has_coerce_map_from(PolynomialRing(ZZ, 't')) True sage: S.has_coerce_map_from(LaurentPolynomialRing(ZZ, 't')) True sage: S.has_coerce_map_from(PowerSeriesRing(ZZ, 't')) True sage: S.has_coerce_map_from(S) True
sage: S.has_coerce_map_from(QQ) False sage: S.has_coerce_map_from(PolynomialRing(QQ, 't')) False sage: S.has_coerce_map_from(LaurentPolynomialRing(QQ, 't')) False sage: S.has_coerce_map_from(PowerSeriesRing(QQ, 't')) False sage: S.has_coerce_map_from(LaurentSeriesRing(QQ, 't')) False
sage: R.<t> = LaurentSeriesRing(QQ['x']) sage: R.has_coerce_map_from(QQ[['t']]) True sage: R.has_coerce_map_from(QQ['t']) True sage: R.has_coerce_map_from(ZZ['x']['t']) True sage: R.has_coerce_map_from(ZZ['t']['x']) False sage: R.has_coerce_map_from(ZZ['x']) True """
is_LaurentPolynomialRing(P) or is_PowerSeriesRing(P) or is_PolynomialRing(P)) and P.variable_name() == self.variable_name() and A.has_coerce_map_from(P.base_ring())):
def _is_valid_homomorphism_(self, codomain, im_gens): """ EXAMPLES::
sage: R.<x> = LaurentSeriesRing(GF(17)) sage: S.<y> = LaurentSeriesRing(GF(19)) sage: R.hom([y], S) # indirect doctest Traceback (most recent call last): ... ValueError: relations do not all (canonically) map to 0 under map determined by images of generators sage: f = R.hom(x+x^3,R) sage: f(x^2) x^2 + 2*x^4 + x^6 """ ## NOTE: There are no ring homomorphisms from the ring of ## all formal power series to most rings, e.g, the p-adic ## field, since you can always (mathematically!) construct ## some power series that doesn't converge. ## Note that 0 is not a *ring* homomorphism.
def characteristic(self): """ EXAMPLES::
sage: R.<x> = LaurentSeriesRing(GF(17)) sage: R.characteristic() 17 """
def residue_field(self): """ Return the residue field of this Laurent series field if it is a complete discrete valuation field (i.e. if the base ring is a field, in which base it is also the residue field).
EXAMPLES::
sage: R.<x> = LaurentSeriesRing(GF(17)) sage: R.residue_field() Finite Field of size 17
sage: R.<x> = LaurentSeriesRing(ZZ) sage: R.residue_field() Traceback (most recent call last): ... TypeError: the base ring is not a field """
def set_default_prec(self, n): """ Set the default precision.
This method is deprecated.
TESTS::
sage: R.<x> = LaurentSeriesRing(QQ) sage: R.set_default_prec(3) doctest:...: DeprecationWarning: This method is deprecated. See http://trac.sagemath.org/16201 for details. sage: 1/(x^5-x^7) x^-5 + x^-3 + O(x^-2) """
def default_prec(self): """ Get the precision to which exact elements are truncated when necessary (most frequently when inverting).
EXAMPLES::
sage: R.<x> = LaurentSeriesRing(QQ, default_prec=5) sage: R.default_prec() 5 """
def is_exact(self): """ Laurent series rings are inexact.
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.is_exact() False """
@cached_method def gen(self, n=0): """ EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.gen() x """ raise IndexError("generator {} not defined".format(n))
def uniformizer(self): """ Return a uniformizer of this Laurent series field if it is a discrete valuation field (i.e. if the base ring is actually a field). Otherwise, an error is raised.
EXAMPLES::
sage: R.<t> = LaurentSeriesRing(QQ) sage: R.uniformizer() t
sage: R.<t> = LaurentSeriesRing(ZZ) sage: R.uniformizer() Traceback (most recent call last): ... TypeError: the base ring is not a field """
def ngens(self): """ Laurent series rings are univariate.
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.ngens() 1 """
def polynomial_ring(self): r""" If this is the Laurent series ring `R((t))`, return the polynomial ring `R[t]`.
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.polynomial_ring() Univariate Polynomial Ring in x over Rational Field """ sparse=self.is_sparse())
def laurent_polynomial_ring(self): r""" If this is the Laurent series ring `R((t))`, return the Laurent polynomial ring `R[t,1/t]`.
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.laurent_polynomial_ring() Univariate Laurent Polynomial Ring in x over Rational Field """ sparse=self.is_sparse())
def power_series_ring(self): r""" If this is the Laurent series ring `R((t))`, return the power series ring `R[[t]]`.
EXAMPLES::
sage: R = LaurentSeriesRing(QQ, "x") sage: R.power_series_ring() Power Series Ring in x over Rational Field """
|