Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/sage/rings/laurent_series_ring_element.pyi
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import builtins
from typing import Any


class LaurentSeriesRingElement:
def __init__(self, parent: Any, f: Any, n: int = 0) -> None: ...
def __reduce__(self) -> tuple: ...
Expand Down Expand Up @@ -68,3 +69,4 @@ class LaurentSeriesRingElement:
def inverse(self) -> LaurentSeriesRingElement: ...
def __call__(self, *x: Any, **kwds: Any) -> LaurentSeriesRingElement: ...
def __pari__(self) -> Any: ...
def map_coefficients(self, f: Any, new_base_ring: Any = None) -> LaurentSeriesRingElement: ...
196 changes: 170 additions & 26 deletions src/sage/rings/laurent_series_ring_element.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -78,14 +78,6 @@ from sage.structure.richcmp cimport richcmp_not_equal, rich_to_bool
from sage.misc.derivative import multi_derivative


def is_LaurentSeries(x):
from sage.misc.superseded import deprecation_cython
deprecation_cython(38266,
"The function is_LaurentSeries is deprecated; "
"use 'isinstance(..., LaurentSeries)' instead.")
return isinstance(x, LaurentSeries)


cdef class LaurentSeries(AlgebraElement):
r"""
A Laurent Series.
Expand Down Expand Up @@ -175,6 +167,18 @@ cdef class LaurentSeries(AlgebraElement):
self.__u = parent._power_series_ring(f >> val)

def __reduce__(self):
"""
For pickling.

EXAMPLES::

sage: R.<q> = LaurentSeriesRing(ZZ)
sage: p = R([1,2,3])
sage: loads(dumps(p)) == p
True
sage: type(p)
<class 'sage.rings.laurent_series_ring_element.LaurentSeries'>
"""
return self._parent, (self.__u, self.__n)

def change_ring(self, R):
Expand Down Expand Up @@ -222,6 +226,8 @@ cdef class LaurentSeries(AlgebraElement):

def is_zero(self):
"""
Return ``True`` is ``self`` is zero.

EXAMPLES::

sage: x = Frac(QQ[['x']]).0
Expand Down Expand Up @@ -382,9 +388,9 @@ cdef class LaurentSeries(AlgebraElement):

sage: R.<x> = LaurentSeriesRing(QQ)
sage: f = -1/x + 1 + 2*x^2 + 5*x^5
sage: f.V(2)
sage: f.verschiebung(2)
-x^-2 + 1 + 2*x^4 + 5*x^10
sage: f.V(-1)
sage: f.verschiebung(-1)
5*x^-5 + 2*x^-2 + 1 - x
sage: h = f.add_bigoh(7)
sage: h.V(2)
Expand Down Expand Up @@ -504,6 +510,16 @@ cdef class LaurentSeries(AlgebraElement):
return s[1:]

def __hash__(self):
"""
Return the hash of ``self``.

EXAMPLES::

sage: R.<t> = LaurentSeriesRing(QQ)
sage: f = -5/t^(10) + t + t^2 - 10/3*t^3
sage: hash(f) # random
-3700306575898560102
"""
return hash(self.__u) ^ self.__n

def __getitem__(self, i):
Expand Down Expand Up @@ -576,6 +592,12 @@ cdef class LaurentSeries(AlgebraElement):

def list(self):
"""
Return ``self`` as a ``list``.

.. SEEALSO::

:meth:`sage.rings.power_series_ring_element.PowerSeries.list`

EXAMPLES::

sage: R.<t> = LaurentSeriesRing(QQ)
Expand Down Expand Up @@ -933,9 +955,29 @@ cdef class LaurentSeries(AlgebraElement):
self.__n + right.__n)

cpdef _rmul_(self, Element c):
"""
Multiply ``self`` on the right by a scalar ``c``.

EXAMPLES::

sage: R.<t> = LaurentSeriesRing(GF(7))
sage: f = t^(-1) + 3*t^4 + O(t^11)
sage: f * GF(7)(3)
3*t^-1 + 2*t^4 + O(t^11)
"""
return type(self)(self._parent, self.__u._rmul_(c), self.__n)

cpdef _lmul_(self, Element c):
"""
Multiply ``self`` on the left by a scalar ``c``.

EXAMPLES::

sage: R.<t> = LaurentSeriesRing(GF(11))
sage: f = t^(-2) + 1 + 3*t^4 + O(t^120)
sage: 2 * f
2*t^-2 + 2 + 6*t^4 + O(t^120)
"""
return type(self)(self._parent, self.__u._lmul_(c), self.__n)

def __pow__(_self, r, dummy):
Expand Down Expand Up @@ -1021,14 +1063,36 @@ cdef class LaurentSeries(AlgebraElement):
return type(self)(self._parent, self.__u, self.__n + k)

def __lshift__(LaurentSeries self, k):
"""
Shift ``self`` to the left by ``k``, i.e. multiply by `x^k`.

EXAMPLES::

sage: R.<t> = LaurentSeriesRing(QQ)
sage: f = t^(-6) + 1 + t + t^4
sage: f << 1
t^-5 + t + t^2 + t^5
"""
return type(self)(self._parent, self.__u, self.__n + k)

def __rshift__(LaurentSeries self, k):
"""
Shift ``self`` to the right by ``k``, i.e. multiply by `x^{-k}`.

EXAMPLES::

sage: R.<t> = LaurentSeriesRing(GF(2))
sage: f = t + t^4 + O(t^7)
sage: f >> 1
1 + t^3 + O(t^6)
sage: f >> 10
t^-9 + t^-6 + O(t^-3)
"""
return type(self)(self._parent, self.__u, self.__n - k)

def truncate(self, long n):
r"""
Return the Laurent series of degree ` < n` which is
Return the Laurent series of degree `< n` which is
equivalent to ``self`` modulo `x^n`.

EXAMPLES::
Expand All @@ -1048,7 +1112,7 @@ cdef class LaurentSeries(AlgebraElement):

def truncate_laurentseries(self, long n):
r"""
Replace any terms of degree >= n by big oh.
Replace any terms of degree `\geq n` by big oh.

EXAMPLES::

Expand Down Expand Up @@ -1292,7 +1356,15 @@ cdef class LaurentSeries(AlgebraElement):
return rich_to_bool(op, 0)

def valuation_zero_part(self):
"""
r"""
Return the part of ``self`` that has valuation 0.

We can write every nonzero Laurent series uniquely as
`l(x) = x^v u(x)`, where `u(x)` is a power series with a nonzero
constant (i.e., `u(0) \neq 0`). Thus `u(x)` has valuation zero
and could be called the "unit part" as it is invertible
(assuming the leading coefficient is a unit).

EXAMPLES::

sage: x = Frac(QQ[['x']]).0
Expand All @@ -1308,7 +1380,11 @@ cdef class LaurentSeries(AlgebraElement):
return self.__u

def valuation(self):
"""
r"""
Return the valuation of ``self``, that is, the minimal `n`
Comment thread
r-mb marked this conversation as resolved.
such that the coefficient of `x^n` is nonzero (by convention
this is `\infty` if ``self`` is zero).

EXAMPLES::

sage: R.<x> = LaurentSeriesRing(QQ)
Expand Down Expand Up @@ -1342,6 +1418,8 @@ cdef class LaurentSeries(AlgebraElement):

def variable(self):
"""
Return the variable name of the parent of ``self``.

EXAMPLES::

sage: x = Frac(QQ[['x']]).0
Expand All @@ -1353,10 +1431,10 @@ cdef class LaurentSeries(AlgebraElement):

def prec(self):
"""
This function returns the n so that the Laurent series is of the
This function returns the `n` so that the Laurent series is of the
form (stuff) + `O(t^n)`. It doesn't matter how many
negative powers appear in the expansion. In particular, prec could
be negative.
negative powers appear in the expansion. In particular, the output
could be negative.

EXAMPLES::

Expand Down Expand Up @@ -1412,16 +1490,28 @@ cdef class LaurentSeries(AlgebraElement):
return self.prec() - self.valuation()

def __copy__(self):
"""
Return a copy of ``self``.

EXAMPLES::

sage: R.<x> = LaurentSeriesRing(ZZ)
sage: f = R.random_element()
sage: g = copy(f)
sage: g == f
True
"""
return type(self)(self._parent, self.__u.__copy__(), self.__n)

def reverse(self, precision=None):
"""
Return the reverse of f, i.e., the series g such that g(f(x)) = x.
Given an optional argument ``precision``, return the reverse with given
precision (note that the reverse can have precision at most
``f.prec()``). If ``f`` has infinite precision, and the argument
``precision`` is not given, then the precision of the reverse defaults
to the default precision of ``f.parent()``.
Return the reverse of ``self``, i.e., the series ``g`` such that
``g(self(x)) = x``. Given an optional argument ``precision``, return
the reverse with given precision (note that the reverse can have
precision at most ``self.prec()``). If ``self`` has infinite
precision, and the argument ``precision`` is not given, then the
precision of the reverse defaults to the default precision of
``self.parent()``.

Note that this is only possible if the valuation of ``self`` is exactly
1.
Expand Down Expand Up @@ -1587,7 +1677,7 @@ cdef class LaurentSeries(AlgebraElement):

# Case 3: The unit part must be a square
unit_part = (self >> v).power_series()

# We use a try-except block to handle inconsistent API in base rings
try:
# Check is_square without keyword args first (safest)
Expand All @@ -1607,7 +1697,7 @@ cdef class LaurentSeries(AlgebraElement):
sqrt_unit = unit_part.sqrt()
except (ValueError, ArithmeticError):
return False, None

# Reconstruct: t^(v/2) * sqrt(unit)
return True, self.parent()(sqrt_unit) << (v // 2)
else:
Expand Down Expand Up @@ -1874,7 +1964,7 @@ cdef class LaurentSeries(AlgebraElement):

def inverse(self):
"""
Return the inverse of self, i.e., self^(-1).
Return the inverse of ``self``, i.e., ``self^(-1)``.

EXAMPLES::

Expand Down Expand Up @@ -1981,3 +2071,57 @@ cdef class LaurentSeries(AlgebraElement):
f = self.__u
x = f.parent().gen()
return f.__pari__() * x.__pari__()**self.__n

def map_coefficients(self, f, new_base_ring=None):
r"""
Return the series obtained by applying ``f`` to the nonzero
coefficients of ``self``.

If ``f`` is a :class:`sage.categories.map.Map`, then the resulting
series will be defined over the codomain of ``f``. Otherwise, the
resulting series will be over the same ring as ``self``. Set
``new_base_ring`` to override this behaviour.

INPUT:

- ``f`` -- a callable that will be applied to the coefficients
of``self``
- ``new_base_ring`` -- commutative ring (optional) if given,
the resulting series will be defined over this ring

EXAMPLES::

sage: R.<x> = LaurentSeriesRing(SR)
sage: f = (1+I)*x^2 + 3*x - I + x^(-2)
sage: f.map_coefficients(lambda z: z.conjugate())
x^-2 + I + 3*x + (-I + 1)*x^2
sage: R.<x> = LaurentSeriesRing(ZZ)
sage: f = x^2 - 2*x + 1 + 2 * x^(-1)
sage: f.map_coefficients(lambda t: t - 1)
x^-1 - 3*x

Examples with a new base ring::

sage: R.<x> = LaurentSeriesRing(ZZ)
sage: k = GF(5)
sage: residue = lambda x: k(x)
sage: f = 4*x^2 + x + 8 + 5*x^(-1) - 1*x^(-2)
sage: g = f.map_coefficients(residue); g
4*x^-2 + 3 + x + 4*x^2
sage: g.parent()
Laurent Series Ring in x over Integer Ring
sage: g = f.map_coefficients(residue, new_base_ring=k); g
4*x^-2 + 3 + x + 4*x^2
sage: g.parent()
Laurent Series Ring in x over Finite Field of size 5
sage: residue = k.coerce_map_from(ZZ)
sage: g = f.map_coefficients(residue); g
4*x^-2 + 3 + x + 4*x^2
sage: g.parent()
Laurent Series Ring in x over Finite Field of size 5
"""
unit = self.__u
res = unit.map_coefficients(f, new_base_ring)
if res.base_ring() != unit.base_ring():
return self.parent().change_ring(res.base_ring())(res, self.__n)
return self.parent()(res, self.__n)
Loading