Skip to content
This repository has been archived by the owner on Jan 30, 2023. It is now read-only.

Commit

Permalink
Refactoring out the CS_exact polynomial creation and doc fixes.
Browse files Browse the repository at this point in the history
  • Loading branch information
Travis Scrimshaw committed Aug 4, 2021
1 parent e31b75e commit d75d44c
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 37 deletions.
8 changes: 8 additions & 0 deletions src/sage/data_structures/coefficient_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -478,6 +478,14 @@ def __eq__(self, other):
and self._initial_coefficients == other._initial_coefficients
and self._constant == other._constant)

def polynomial_part(self, gen):
"""
Return the initial part of ``self`` as a polynomial in ``gen``.
"""
R = gen.parent()
v = self._approximate_valuation
return R(sum(val * gen**(v+i) for i, val in enumerate(self._initial_coefficients)))


class CoefficientStream_recursive(CoefficientStream_inexact):
r"""
Expand Down
114 changes: 77 additions & 37 deletions src/sage/rings/lazy_laurent_series.py
Original file line number Diff line number Diff line change
Expand Up @@ -409,7 +409,7 @@ def define(self, s):
r"""
Define an equation by ``self = s``.
INPUT::
INPUT:
- ``s`` -- a Laurent polynomial
Expand Down Expand Up @@ -584,7 +584,7 @@ def _add_(self, other):
- ``other`` -- other series
EXAMPLES::
EXAMPLES:
Dense series can be added::
Expand Down Expand Up @@ -641,7 +641,7 @@ def _sub_(self, other):
- ``other`` -- other series
EXAMPLES::
EXAMPLES:
Dense series can be subtracted::
Expand Down Expand Up @@ -698,15 +698,15 @@ def _sub_(self, other):
return P.element_class(P, CoefficientStream_sub(self._coeff_stream, other._coeff_stream))

def _lmul_(self, scalar):
"""
r"""
Scalar multiplication for module elements with the module
element on the left and the scalar on the right.
INPUT:
- ``scalar`` -- an element of the base ring
EXAMPLES::
EXAMPLES:
Dense series can be multiplied with a scalar::
Expand Down Expand Up @@ -785,9 +785,9 @@ def _lmul_(self, scalar):

def _neg_(self):
"""
Return the negative of this series.
Return the negative of ``self``.
EXAMPLES::
EXAMPLES:
Dense series can be negated::
Expand Down Expand Up @@ -893,7 +893,7 @@ def change_ring(self, ring):
- ``ring`` -- a ring
EXAMPLES::
EXAMPLES:
Dense Implementation::
Expand Down Expand Up @@ -1049,6 +1049,8 @@ def __call__(self, g):
z^-2 + z + z^2 + z^3 + z^4 + ...
sage: fpy = fp(y^2); fpy
y^-4 + y^2 + ...
sage: fpy.parent() is LS
True
sage: [fpy[i] for i in range(-4,11)]
[1, 0, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1]
Expand Down Expand Up @@ -1096,7 +1098,7 @@ def __call__(self, g):
1 + y^4 - 2*y^5 + 2*y^6 + ...
sage: z(y)
y
We look at cases where the composition does not exist.
`g = 0` and `val(f) < 0`::
Expand Down Expand Up @@ -1152,22 +1154,24 @@ def __call__(self, g):
# constant polynomial
R = self.parent()._laurent_poly_ring
z = R.gen()
poly = R(sum([self._coeff_stream[i] * z**i for i in range(self._coeff_stream._approximate_valuation, self._coeff_stream._degree)]))
poly = self._coeff_stream.polynomial_part(z)
if poly.is_constant():
return self
if not isinstance(g, LazyLaurentSeries):
return poly(g)
# g also has finite length, compose the polynomials
if isinstance(g._coeff_stream, CoefficientStream_exact) and not g._coeff_stream._constant:
R = P._laurent_poly_ring
g_poly = g._coeff_stream.polynomial_part(R.gen())
try:
R = P._laurent_poly_ring
g_poly = R(sum([g._coeff_stream[i] * z**i for i in range(g._coeff_stream._approximate_valuation, g._coeff_stream._degree)]))
ret = poly(g_poly)
if ret.parent() is R:
initial_coefficients = [ret[i] for i in range(ret.valuation(), ret.degree() + 1)]
return P.element_class(P, CoefficientStream_exact(initial_coefficients, self._coeff_stream._is_sparse, valuation=ret.valuation()))
except TypeError: # the result is not a Laurent polynomial
pass
except (ValueError, TypeError): # the result is not a Laurent polynomial
ret = None
if ret is not None and ret.parent() is R:
val = ret.valuation()
deg = ret.degree() + 1
initial_coefficients = [ret[i] for i in range(val, deg)]
return P.element_class(P, CoefficientStream_exact(initial_coefficients, self._coeff_stream._is_sparse, 0, deg, val))

# Return the sum since g is not known to be finite or we do not get a Laurent polynomial
# TODO: Optimize when f has positive valuation
Expand Down Expand Up @@ -1210,11 +1214,11 @@ def _mul_(self, other):
- ``other`` -- other series
EXAMPLES::
EXAMPLES:
Lazy Laurent series that are known to be exact can be multiplied::
sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=False)
sage: (1 - z)*(1 - z)
1 - 2*z + z^2
sage: (1 - z)*(1 - z)*(1 - z)
Expand All @@ -1229,6 +1233,17 @@ def _mul_(self, other):
sage: N
z + z^2 - z^3 - 6*z^4 - 15*z^5 - 29*z^6 + ...
sage: z * M
z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + 6*z^7 + ...
sage: M * z^-2
z^-1 + 2 + 3*z + 4*z^2 + 5*z^3 + 6*z^4 + ...
sage: L.one() * M is M
True
sage: M * L.one() is M
True
We check the sparse implementation::
sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
sage: M = L(lambda n: n); M
Expand All @@ -1237,6 +1252,10 @@ def _mul_(self, other):
1 + z + z^2 + z^3 + z^4 + z^5 + z^6 + ...
sage: M * N
z + 3*z^2 + 6*z^3 + 10*z^4 + 15*z^5 + 21*z^6 + ...
sage: z * M
z^2 + 2*z^3 + 3*z^4 + 4*z^5 + 5*z^6 + 6*z^7 + ...
sage: M * z^-2
z^-1 + 2 + 3*z + 4*z^2 + 5*z^3 + 6*z^4 + ...
sage: L.one() * M is M
True
Expand All @@ -1253,20 +1272,19 @@ def _mul_(self, other):
z = R.gen()
if isinstance(left, CoefficientStream_exact):
if not left._constant:
pl = R(sum([left[i] * z**i for i in range(left._approximate_valuation, left._degree)]))
if pl == R.one(): # self == 1
if left._approximate_valuation == 0 and left._initial_coefficients == (1,): # self == 1
return other
pl = left.polynomial_part(z)
if isinstance(right, CoefficientStream_exact):
if not right._constant:
pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)]))
pr = right.polynomial_part(z)
p = pl * pr
c = left._constant
initial_coefficients = [p[i] for i in range(p.valuation(), p.degree() + 1)]
return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, valuation=p.valuation(), constant=c))
elif isinstance(right, CoefficientStream_exact):
if not right._constant:
pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)]))
if pr == R.one(): # other == 1
if right._approximate_valuation == 0 and right._initial_coefficients == (1,): # other == 1
return self
return P.element_class(P, CoefficientStream_cauchy_product(self._coeff_stream, other._coeff_stream))

Expand All @@ -1293,7 +1311,7 @@ def _div_(self, other):
- ``other`` -- nonzero series
EXAMPLES::
EXAMPLES:
Lazy Laurent series that have a dense implementation can be divided::
Expand Down Expand Up @@ -1337,8 +1355,8 @@ def _div_(self, other):
if not left._constant and not right._constant:
R = P._laurent_poly_ring
z = R.gen()
pl = R(sum([left[i] * z**i for i in range(left._approximate_valuation, left._degree)]))
pr = R(sum([right[i] * z**i for i in range(right._approximate_valuation, right._degree)]))
pl = left.polynomial_part(z)
pr = right.polynomial_part(z)
ret = pl / pr
try:
ret = P._laurent_poly_ring(ret)
Expand All @@ -1354,7 +1372,7 @@ def __invert__(self):
"""
Return the multiplicative inverse of the element.
EXAMPLES::
EXAMPLES:
Lazy Laurent series that have a dense implementation can be inverted::
Expand Down Expand Up @@ -1405,9 +1423,10 @@ def __pow__(self, n):
- ``n`` -- integer; the power to which to raise the series
EXAMPLES::
EXAMPLES:
Lazy Laurent series that have a dense implementation can be raised to the power ``n``::
Lazy Laurent series that have a dense implementation can be
raised to the power ``n``::
sage: L.<z> = LazyLaurentSeriesRing(ZZ)
sage: (1 - z)^-1
Expand All @@ -1420,18 +1439,26 @@ def __pow__(self, n):
1 + 3*z + 6*z^2 + 10*z^3 + 15*z^4 + 21*z^5 + 28*z^6 + ...
sage: M = L(lambda n: n); M
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ...
sage: M ^ 2
sage: M^2
z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + ...
Lazy Laurent series that have a sparse implementation can be raised to the power ``n``::
We can create a really large power of a monomial, even with
the dense implementation::
sage: z^1000000
z^1000000
Lazy Laurent series that have a sparse implementation can be
raised to the power ``n``::
sage: L.<z> = LazyLaurentSeriesRing(ZZ, sparse=True)
sage: M = L(lambda n: n); M
z + 2*z^2 + 3*z^3 + 4*z^4 + 5*z^5 + 6*z^6 + ...
sage: M ^ 2
sage: M^2
z^2 + 4*z^3 + 10*z^4 + 20*z^5 + 35*z^6 + ...
Lazy Laurent series that are known to be exact can be raised to the power ``n``::
Lazy Laurent series that are known to be exact can be raised
to the power ``n``::
sage: z^2
z^2
Expand All @@ -1443,6 +1470,18 @@ def __pow__(self, n):
if n == 0:
return self.parent().one()

cs = self._coeff_stream
if (isinstance(cs, CoefficientStream_exact)
and not cs._constant and n in ZZ
and (n > 0 or len(cs._initial_coefficients) == 1)):
P = self.parent()
z = P._laurent_poly_ring.gen()
ret = cs.polynomial_part(z) ** ZZ(n)
val = ret.valuation()
deg = ret.degree() + 1
initial_coefficients = [ret[i] for i in range(val, deg)]
return P.element_class(P, CoefficientStream_exact(initial_coefficients, P._sparse, self._coeff_stream._constant, deg, val))

return generic_power(self, n)

def approximate_series(self, prec, name=None):
Expand Down Expand Up @@ -1493,13 +1532,13 @@ def approximate_series(self, prec, name=None):

def polynomial(self, degree=None, name=None):
r"""
Return the polynomial or Laurent polynomial if the series is actually so.
Return ``self`` as a Laurent polynomial if ``self`` is actually so.
INPUT:
- ``degree`` -- ``None`` or an integer
- ``name`` -- name of the variable; if it is ``None``, the name of the variable
of the series is used
- ``name`` -- name of the variable; if it is ``None``, the name of
the variable of the series is used
OUTPUT:
Expand Down Expand Up @@ -1612,3 +1651,4 @@ def _repr_(self):
ret = repr(R([self._coeff_stream[i] for i in range(v, m)]).shift(v))
# TODO: Better handling when ret == 0 but we have not checked up to the constant term
return ret + ' + ...'

0 comments on commit d75d44c

Please sign in to comment.