Skip to content

Commit 4098dbf

Browse files
committed
add derivative for LazyLaurentSeries
1 parent 6eebb35 commit 4098dbf

File tree

2 files changed

+160
-5
lines changed

2 files changed

+160
-5
lines changed

src/sage/data_structures/stream.py

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@
9797
from sage.rings.integer_ring import ZZ
9898
from sage.rings.infinity import infinity
9999
from sage.arith.misc import divisors
100+
from sage.misc.misc_c import prod
100101
from sage.combinat.integer_vector_weighted import iterator_fast as wt_int_vec_iter
101102

102103
class Stream():
@@ -2347,7 +2348,7 @@ def __init__(self, series, shift):
23472348
sage: from sage.data_structures.stream import Stream_exact
23482349
sage: h = Stream_exact([1], False, constant=3)
23492350
sage: M = Stream_shift(h, 2)
2350-
sage: TestSuite(M).run()
2351+
sage: TestSuite(M).run(skip="_test_pickling")
23512352
"""
23522353
self._series = series
23532354
self._shift = shift
@@ -2424,3 +2425,113 @@ def is_nonzero(self):
24242425
True
24252426
"""
24262427
return self._series.is_nonzero()
2428+
2429+
class Stream_derivative(Stream_inexact):
2430+
"""
2431+
Operator for taking derivatives of a stream.
2432+
2433+
INPUT:
2434+
2435+
- ``series`` -- a :class:`Stream`
2436+
- ``shift`` -- a positive integer
2437+
"""
2438+
def __init__(self, series, shift):
2439+
"""
2440+
Initialize ``self``.
2441+
2442+
EXAMPLES::
2443+
2444+
sage: from sage.data_structures.stream import Stream_exact, Stream_derivative
2445+
sage: f = Stream_exact([1,2,3], False)
2446+
sage: f2 = Stream_derivative(f, 2)
2447+
sage: TestSuite(f2).run()
2448+
"""
2449+
self._series = series
2450+
self._shift = shift
2451+
if 0 <= series._approximate_order <= shift:
2452+
aorder = 0
2453+
else:
2454+
aorder = series._approximate_order - shift
2455+
super().__init__(series._is_sparse, aorder)
2456+
2457+
def __getitem__(self, n):
2458+
"""
2459+
Return the ``n``-th coefficient of ``self``.
2460+
2461+
EXAMPLES::
2462+
2463+
sage: from sage.data_structures.stream import Stream_function, Stream_derivative
2464+
sage: f = Stream_function(lambda n: 1/n if n else 0, QQ, True, -2)
2465+
sage: [f[i] for i in range(-5, 3)]
2466+
[0, 0, 0, -1/2, -1, 0, 1, 1/2]
2467+
sage: f2 = Stream_derivative(f, 2)
2468+
sage: [f2[i] for i in range(-5, 3)]
2469+
[0, -3, -2, 0, 0, 1, 2, 3]
2470+
2471+
sage: f = Stream_function(lambda n: 1/n, QQ, True, 2)
2472+
sage: [f[i] for i in range(-1, 4)]
2473+
[0, 0, 0, 1/2, 1/3]
2474+
sage: f2 = Stream_derivative(f, 3)
2475+
sage: [f2[i] for i in range(-1, 4)]
2476+
[0, 2, 6, 12, 20]
2477+
"""
2478+
return (prod(n+k for k in range(1, self._shift + 1))
2479+
* self._series[n + self._shift])
2480+
2481+
def __hash__(self):
2482+
"""
2483+
Return the hash of ``self``.
2484+
2485+
EXAMPLES::
2486+
2487+
sage: from sage.data_structures.stream import Stream_function
2488+
sage: from sage.data_structures.stream import Stream_derivative
2489+
sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1)
2490+
sage: f = Stream_derivative(a, 1)
2491+
sage: g = Stream_derivative(a, 2)
2492+
sage: hash(f) == hash(f)
2493+
True
2494+
sage: hash(f) == hash(g)
2495+
False
2496+
2497+
"""
2498+
return hash((type(self), self._series, self._shift))
2499+
2500+
def __eq__(self, other):
2501+
"""
2502+
Test equality.
2503+
2504+
INPUT:
2505+
2506+
- ``other`` -- a stream of coefficients
2507+
2508+
EXAMPLES::
2509+
2510+
sage: from sage.data_structures.stream import Stream_function
2511+
sage: from sage.data_structures.stream import Stream_derivative
2512+
sage: a = Stream_function(lambda n: 2*n, ZZ, False, 1)
2513+
sage: f = Stream_derivative(a, 1)
2514+
sage: g = Stream_derivative(a, 2)
2515+
sage: f == g
2516+
False
2517+
sage: f == Stream_derivative(a, 1)
2518+
True
2519+
"""
2520+
return (isinstance(other, type(self)) and self._shift == other._shift
2521+
and self._series == other._series)
2522+
2523+
def is_nonzero(self):
2524+
r"""
2525+
Return ``True`` if and only if this stream is known
2526+
to be nonzero.
2527+
2528+
EXAMPLES::
2529+
2530+
sage: from sage.data_structures.stream import Stream_exact, Stream_derivative
2531+
sage: f = Stream_exact([1,2], False)
2532+
sage: Stream_derivative(f, 1).is_nonzero()
2533+
True
2534+
sage: Stream_derivative(f, 2).is_nonzero() # it might be nice if this gave False
2535+
True
2536+
"""
2537+
return self._series.is_nonzero()

src/sage/rings/lazy_series.py

Lines changed: 48 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,7 @@
118118
from sage.structure.richcmp import op_EQ, op_NE
119119
from sage.functions.other import factorial
120120
from sage.arith.power import generic_power
121+
from sage.misc.misc_c import prod
121122
from sage.rings.infinity import infinity
122123
from sage.rings.integer_ring import ZZ
123124
from sage.rings.polynomial.laurent_polynomial_ring import LaurentPolynomialRing
@@ -137,6 +138,7 @@
137138
Stream_uninitialized,
138139
Stream_shift,
139140
Stream_function,
141+
Stream_derivative,
140142
Stream_dirichlet_convolve,
141143
Stream_dirichlet_invert,
142144
Stream_plethysm
@@ -323,10 +325,10 @@ def map_coefficients(self, func, ring=None):
323325
if not any(initial_coefficients) and not c:
324326
return P.zero()
325327
coeff_stream = Stream_exact(initial_coefficients,
326-
self._coeff_stream._is_sparse,
327-
order=coeff_stream._approximate_order,
328-
degree=coeff_stream._degree,
329-
constant=BR(c))
328+
self._coeff_stream._is_sparse,
329+
order=coeff_stream._approximate_order,
330+
degree=coeff_stream._degree,
331+
constant=BR(c))
330332
return P.element_class(P, coeff_stream)
331333
R = P._internal_poly_ring.base_ring()
332334
coeff_stream = Stream_map_coefficients(self._coeff_stream, func, R)
@@ -3081,6 +3083,48 @@ def revert(self):
30813083

30823084
compositional_inverse = revert
30833085

3086+
def derivative(self, order=1):
3087+
"""
3088+
Return the derivative of the Laurent series.
3089+
3090+
INPUT:
3091+
3092+
- ``order`` -- optional integer (default 1)
3093+
3094+
EXAMPLES::
3095+
3096+
sage: L.<z> = LazyLaurentSeriesRing(ZZ)
3097+
sage: z.derivative()
3098+
1
3099+
sage: (1+z+z^2).derivative(3)
3100+
0
3101+
sage: (1/z).derivative()
3102+
-z^-2
3103+
sage: (1/(1-z)).derivative()
3104+
1 + 2*z + 3*z^2 + 4*z^3 + 5*z^4 + 6*z^5 + 7*z^6 + O(z^7)
3105+
3106+
"""
3107+
P = self.parent()
3108+
coeff_stream = self._coeff_stream
3109+
if isinstance(coeff_stream, Stream_zero):
3110+
return self
3111+
BR = P.base_ring()
3112+
if (isinstance(coeff_stream, Stream_exact)
3113+
and not coeff_stream._constant):
3114+
if coeff_stream._approximate_order >= 0 and coeff_stream._degree <= order:
3115+
return P.zero()
3116+
initial_coefficients = [prod(i-k for k in range(order)) * c
3117+
for i, c in enumerate(coeff_stream._initial_coefficients,
3118+
coeff_stream._approximate_order)]
3119+
coeff_stream = Stream_exact(initial_coefficients,
3120+
self._coeff_stream._is_sparse,
3121+
order=coeff_stream._approximate_order - order,
3122+
constant=coeff_stream._constant)
3123+
return P.element_class(P, coeff_stream)
3124+
3125+
coeff_stream = Stream_derivative(self._coeff_stream, order)
3126+
return P.element_class(P, coeff_stream)
3127+
30843128
def approximate_series(self, prec, name=None):
30853129
r"""
30863130
Return the Laurent series with absolute precision ``prec`` approximated

0 commit comments

Comments
 (0)