Skip to content

Commit

Permalink
sagemathgh-38741: move power series to Parent
Browse files Browse the repository at this point in the history
    
make the power series rings inherit from Parent instead of the auld
`Ring` class

### 📝 Checklist

- [x] The title is concise and informative.
- [x] The description explains in detail what this PR is about.
- [ ] I have linked a relevant issue or discussion.
- [ ] I have created tests covering the changes.
- [ ] I have updated the documentation and checked the documentation
preview.
    
URL: sagemath#38741
Reported by: Frédéric Chapoton
Reviewer(s): Frédéric Chapoton, Martin Rubey
  • Loading branch information
Release Manager committed Oct 5, 2024
2 parents 3dd0603 + 576784f commit c6f35da
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 22 deletions.
21 changes: 17 additions & 4 deletions src/sage/rings/multi_power_series_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -213,8 +213,8 @@
from sage.rings.polynomial.multi_polynomial_ring import MPolynomialRing_base
from sage.rings.polynomial.term_order import TermOrder
from sage.rings.power_series_ring import PowerSeriesRing, PowerSeriesRing_generic
from sage.rings.ring import CommutativeRing
from sage.structure.nonexact import Nonexact
from sage.structure.parent import Parent

from sage.categories.commutative_rings import CommutativeRings
_CommutativeRings = CommutativeRings()
Expand Down Expand Up @@ -389,8 +389,9 @@ def __init__(self, base_ring, num_gens, name_list,
# Multivariate power series rings inherit from power series rings. But
# apparently we can not call their initialisation. Instead, initialise
# CommutativeRing and Nonexact:
CommutativeRing.__init__(self, base_ring, name_list, category=_IntegralDomains if base_ring in
_IntegralDomains else _CommutativeRings)
Parent.__init__(self, base=base_ring, names=name_list,
category=_IntegralDomains if base_ring in
_IntegralDomains else _CommutativeRings)
Nonexact.__init__(self, default_prec)

# underlying polynomial ring in which to represent elements
Expand Down Expand Up @@ -1005,7 +1006,7 @@ def gen(self, n=0):
if n < 0 or n >= self._ngens:
raise ValueError("Generator not defined.")
#return self(self._poly_ring().gens()[int(n)])
return self.element_class(parent=self,x=self._poly_ring().gens()[int(n)], is_gen=True)
return self.element_class(parent=self, x=self._poly_ring().gens()[int(n)], is_gen=True)

def ngens(self):
"""
Expand All @@ -1019,6 +1020,18 @@ def ngens(self):
"""
return self._ngens

def gens(self) -> tuple:
"""
Return the generators of this ring.
EXAMPLES::
sage: M = PowerSeriesRing(ZZ, 3, 'v')
sage: M.gens()
(v0, v1, v2)
"""
return tuple(self.gen(i) for i in range(self._ngens))

def prec_ideal(self):
"""
Return the ideal which determines precision; this is the ideal
Expand Down
52 changes: 34 additions & 18 deletions src/sage/rings/power_series_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,8 @@
x - 1/6*x^3 + 1/120*x^5 - 1/5040*x^7 + 1/362880*x^9 + O(x^10)
sage: R.<x> = PowerSeriesRing(QQ, default_prec=15)
sage: sin(x)
x - 1/6*x^3 + 1/120*x^5 - 1/5040*x^7 + 1/362880*x^9 - 1/39916800*x^11 + 1/6227020800*x^13 + O(x^15)
x - 1/6*x^3 + 1/120*x^5 - 1/5040*x^7 + 1/362880*x^9 - 1/39916800*x^11
+ 1/6227020800*x^13 + O(x^15)
An iterated example::
Expand Down Expand Up @@ -139,8 +140,6 @@
from sage.misc.lazy_import import lazy_import
from sage.rings import (
integer,
laurent_series_ring,
laurent_series_ring_element,
power_series_mpoly,
power_series_poly,
power_series_ring_element,
Expand All @@ -153,6 +152,7 @@
from sage.rings.polynomial.polynomial_ring_constructor import PolynomialRing
from sage.structure.category_object import normalize_names
from sage.structure.element import Expression, parent
from sage.structure.parent import Parent
from sage.structure.nonexact import Nonexact
from sage.structure.unique_representation import UniqueRepresentation

Expand Down Expand Up @@ -355,7 +355,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None,
* :func:`sage.misc.defaults.set_series_precision`
"""
#multivariate case:
# multivariate case:
# examples for first case:
# PowerSeriesRing(QQ,'x,y,z')
# PowerSeriesRing(QQ,['x','y','z'])
Expand All @@ -364,7 +364,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None,
names = name
if isinstance(names, (tuple, list)) and len(names) > 1 or (isinstance(names, str) and ',' in names):
return _multi_variate(base_ring, num_gens=arg2, names=names,
order=order, default_prec=default_prec, sparse=sparse)
order=order, default_prec=default_prec, sparse=sparse)
# examples for second case:
# PowerSeriesRing(QQ,3,'t')
if arg2 is None and num_gens is not None:
Expand All @@ -373,7 +373,7 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None,
if (isinstance(arg2, str) and
isinstance(names, (int, integer.Integer))):
return _multi_variate(base_ring, num_gens=names, names=arg2,
order=order, default_prec=default_prec, sparse=sparse)
order=order, default_prec=default_prec, sparse=sparse)

# univariate case: the arguments to PowerSeriesRing used to be
# (base_ring, name=None, default_prec=20, names=None, sparse=False),
Expand All @@ -385,11 +385,10 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None,
elif arg2 is not None:
default_prec = arg2

## too many things (padics, elliptic curves) depend on this behavior,
## so no warning for now.
##
# ## too many things (padics, elliptic curves) depend on this behavior,
# ## so no warning for now.

# if isinstance(name, (int,integer.Integer)) or isinstance(arg2,(int,integer.Integer)):
# if isinstance(name, (int, integer.Integer)) or isinstance(arg2, (int, integer.Integer)):
# deprecation(issue_number, "This behavior of PowerSeriesRing is being deprecated in favor of constructing multivariate power series rings. (See Github issue #1956.)")

# the following is the original, univariate-only code
Expand Down Expand Up @@ -427,16 +426,17 @@ def PowerSeriesRing(base_ring, name=None, arg2=None, names=None,
raise TypeError("base_ring must be a commutative ring")
return R


def _multi_variate(base_ring, num_gens=None, names=None,
order='negdeglex', default_prec=None, sparse=False):
order='negdeglex', default_prec=None, sparse=False):
"""
Construct multivariate power series ring.
"""
if names is None:
raise TypeError("you must specify a variable name or names")

if num_gens is None:
if isinstance(names,str):
if isinstance(names, str):
num_gens = len(names.split(','))
elif isinstance(names, (list, tuple)):
num_gens = len(names)
Expand All @@ -458,6 +458,7 @@ def _multi_variate(base_ring, num_gens=None, names=None,
def _single_variate():
pass


def is_PowerSeriesRing(R):
"""
Return ``True`` if this is a *univariate* power series ring. This is in
Expand Down Expand Up @@ -489,7 +490,8 @@ def is_PowerSeriesRing(R):
else:
return False

class PowerSeriesRing_generic(UniqueRepresentation, ring.CommutativeRing, Nonexact):

class PowerSeriesRing_generic(UniqueRepresentation, Parent, Nonexact):
"""
A power series ring.
"""
Expand Down Expand Up @@ -592,9 +594,9 @@ def __init__(self, base_ring, name=None, default_prec=None, sparse=False,
else:
raise ValueError('unknown power series implementation: %r' % implementation)

ring.CommutativeRing.__init__(self, base_ring, names=name,
category=getattr(self, '_default_category',
_CommutativeRings))
Parent.__init__(self, base=base_ring, names=name,
category=getattr(self, '_default_category',
_CommutativeRings))
Nonexact.__init__(self, default_prec)
if implementation == 'pari':
self.__generator = self.element_class(self, R.gen().__pari__())
Expand Down Expand Up @@ -832,7 +834,7 @@ def _element_constructor_(self, f, prec=infinity, check=True):
elif isinstance(f, LaurentSeries) and f.parent().power_series_ring() is self:
return self(f.power_series(), prec, check=check)
elif isinstance(f, MagmaElement) and str(f.Type()) == 'RngSerPowElt':
v = sage_eval(f.Eltseq())
v = sage_eval(f.Eltseq()) # could use .sage() ?
return self(v) * (self.gen(0)**f.Valuation())
elif isinstance(f, FractionFieldElement):
if self.base_ring().has_coerce_map_from(f.parent()):
Expand All @@ -846,7 +848,8 @@ def _element_constructor_(self, f, prec=infinity, check=True):
if isinstance(f, SymbolicSeries):
if str(f.default_variable()) == self.variable_name():
return self.element_class(self, f.list(),
f.degree(f.default_variable()), check=check)
f.degree(f.default_variable()),
check=check)
else:
raise TypeError("Can only convert series into ring with same variable name.")
else:
Expand Down Expand Up @@ -1097,6 +1100,18 @@ def gen(self, n=0):
raise IndexError("generator n>0 not defined")
return self.__generator

def gens(self) -> tuple:
"""
Return the generators of this ring.
EXAMPLES::
sage: R.<t> = PowerSeriesRing(ZZ)
sage: R.gens()
(t,)
"""
return (self.__generator,)

def uniformizer(self):
"""
Return a uniformizer of this power series ring if it is
Expand Down Expand Up @@ -1357,6 +1372,7 @@ def _get_action_(self, other, op, self_is_left):
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 c6f35da

Please sign in to comment.