Skip to content

Commit

Permalink
Trac #34116: add exact division of power series by coefficient
Browse files Browse the repository at this point in the history
as this is very useful for computations in combinatorics

URL: https://trac.sagemath.org/34116
Reported by: chapoton
Ticket author(s): Frédéric Chapoton, Jonathan Kliem, Travis Scrimshaw
Reviewer(s): Frédéric Chapoton, Jonathan Kliem
  • Loading branch information
Release Manager committed Aug 28, 2022
2 parents 75d9213 + 3525f06 commit 8a4672c
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 4 deletions.
6 changes: 5 additions & 1 deletion src/sage/rings/power_series_poly.pxd
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
from .power_series_ring_element cimport PowerSeries
from sage.rings.polynomial.polynomial_element cimport Polynomial

from sage.categories.action cimport Action

cdef class PowerSeries_poly(PowerSeries):
cdef Polynomial __f

cdef class BaseRingFloorDivAction(Action):
pass

70 changes: 67 additions & 3 deletions src/sage/rings/power_series_poly.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ Power Series Methods
The class ``PowerSeries_poly`` provides additional methods for univariate power series.
"""

from .power_series_ring_element cimport PowerSeries
from sage.structure.element cimport Element, ModuleElement, RingElement
from .infinity import infinity, is_Infinite
Expand Down Expand Up @@ -540,8 +539,8 @@ cdef class PowerSeries_poly(PowerSeries):
prec = self._mul_prec(right_r)
return PowerSeries_poly(self._parent,
self.__f * (<PowerSeries_poly>right_r).__f,
prec = prec,
check = True) # check, since truncation may be needed
prec=prec,
check=True) # check, since truncation may be needed

cpdef _rmul_(self, Element c):
"""
Expand Down Expand Up @@ -1230,3 +1229,68 @@ def make_powerseries_poly_v0(parent, f, prec, is_gen):
t
"""
return PowerSeries_poly(parent, f, prec, 0, is_gen)

cdef class BaseRingFloorDivAction(Action):
"""
The floor division action of the base ring on a formal power series.
"""
cpdef _act_(self, g, x):
r"""
Let ``g`` act on ``x`` under ``self``.
Regardless of whether this is a left or right action, the acting
element comes first.
INPUT:
- ``g`` -- an object with parent ``self.G``
- ``x`` -- an object with parent ``self.US()``
.. WARNING::
This is meant to be a fast internal function, so the
conditions on the input are not checked!
EXAMPLES:
One gets the correct parent with floor division::
sage: A = ZZ[['t']]
sage: f = A([3*2**n for n in range(6)]).O(6)
sage: g = f // 3; g
1 + 2*t + 4*t^2 + 8*t^3 + 16*t^4 + 32*t^5 + O(t^6)
sage: g.parent()
Power Series Ring in t over Integer Ring
whereas the parent is larger with division::
sage: parent(f/3)
Power Series Ring in t over Rational Field
Floor division in case that the power series is not divisible by the divisor::
sage: f = A([2**n for n in range(6)]).O(6)
sage: g = f // 3; g
t^2 + 2*t^3 + 5*t^4 + 10*t^5 + O(t^6)
Another example::
sage: s = polygen(QQ,'s')
sage: A = s.parent()[['t']]
sage: f = A([(s+2)*(s+n) for n in range(5)]).O(5)
sage: g = f // (s + 2); g
s + (s + 1)*t + (s + 2)*t^2 + (s + 3)*t^3 + (s + 4)*t^4 + O(t^5)
sage: g.parent()
Power Series Ring in t over Univariate Polynomial Ring in s
over Rational Field
sage: R.<t> = PowerSeriesRing(QQ)
sage: t // 2
1/2*t
"""
cdef PowerSeries_poly elt = <PowerSeries_poly> x
prec = x.prec()
P = self.US()
g = P.base_ring()(g)
return type(x)(P, elt.__f // g, prec=prec, check=False)

25 changes: 25 additions & 0 deletions src/sage/rings/power_series_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -1288,6 +1288,31 @@ def fraction_field(self):
laurent = self.laurent_series_ring()
return laurent.change_ring(self.base_ring().fraction_field())

def _get_action_(self, other, op, self_is_left):
r"""
Return the actions on ``self`` by ``other`` under ``op``.
EXAMPLES::
sage: R.<t> = PowerSeriesRing(ZZ)
sage: import operator
sage: act = coercion_model.get_action(R, ZZ, operator.floordiv); act
Right action by Integer Ring on Power Series Ring in t over Integer Ring
sage: type(act)
<class 'sage.rings.power_series_poly.BaseRingFloorDivAction'>
sage: coercion_model.get_action(ZZ, R, operator.floordiv) is None
True
sage: R.<t> = PowerSeriesRing(QQ)
sage: coercion_model.get_action(R, ZZ, operator.floordiv)
Right action by Integer Ring on Power Series Ring in t over Rational Field
"""
import operator
if op is operator.floordiv and self_is_left and self.base_ring().has_coerce_map_from(other):
from sage.rings.power_series_poly import BaseRingFloorDivAction
# Floor division by coefficient.
return BaseRingFloorDivAction(other, self, is_left=False)
return super()._get_action_(other, op, self_is_left)

class PowerSeriesRing_over_field(PowerSeriesRing_domain):
_default_category = CompleteDiscreteValuationRings()
Expand Down

0 comments on commit 8a4672c

Please sign in to comment.