Skip to content

Commit

Permalink
gh-37087: use parent in Ore polynomials
Browse files Browse the repository at this point in the history
    
this is using `Parent` in Ore polynomial and fractions

also some typing annotations and other little details in the 2 modified
files.

also moving a method to the category of rings (could go higher in the
hierarchy maybe)

### 📝 Checklist

- [x] The title is concise, informative, and self-explanatory.
- [x] The description explains in detail what this PR is about.
    
URL: #37087
Reported by: Frédéric Chapoton
Reviewer(s): Xavier Caruso
  • Loading branch information
Release Manager committed Feb 1, 2024
2 parents e7d8602 + ab87e17 commit e03f1b8
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 58 deletions.
1 change: 0 additions & 1 deletion src/doc/en/thematic_tutorials/coercion_and_categories.rst
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ This base class provides a lot more methods than a general parent::
'_list',
'_one_element',
'_pseudo_fraction_field',
'_random_nonzero_element',
'_unit_ideal',
'_zero_element',
'_zero_ideal',
Expand Down
28 changes: 28 additions & 0 deletions src/sage/categories/rings.py
Original file line number Diff line number Diff line change
Expand Up @@ -1331,6 +1331,34 @@ def free_module(self, base=None, basis=None, map=True):
raise ValueError("base must be a subring of this ring")
raise NotImplementedError

def _random_nonzero_element(self, *args, **kwds):
"""
Return a random non-zero element in this ring.
The default behaviour of this method is to repeatedly call the
``random_element`` method until a non-zero element is obtained.
In this implementation, all parameters are simply pushed forward
to the ``random_element`` method.
INPUT:
- ``*args``, ``**kwds`` - parameters that can be forwarded to
the ``random_element`` method
EXAMPLES::
sage: ZZ._random_nonzero_element() != 0
True
sage: A = GF((5, 3))
sage: A._random_nonzero_element() != 0
True
"""
while True:
x = self.random_element(*args, **kwds)
if not x.is_zero():
return x

class ElementMethods:
def is_unit(self) -> bool:
r"""
Expand Down
38 changes: 27 additions & 11 deletions src/sage/rings/polynomial/ore_function_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,6 @@
from sage.structure.parent import Parent
from sage.categories.algebras import Algebras
from sage.categories.fields import Fields
from sage.rings.ring import Algebra

from sage.rings.morphism import RingHomomorphism
from sage.categories.homset import Hom
Expand All @@ -167,7 +166,7 @@
# Generic implementation of Ore function fields
###############################################

class OreFunctionField(Algebra, UniqueRepresentation):
class OreFunctionField(Parent, UniqueRepresentation):
r"""
A class for fraction fields of Ore polynomial rings.
"""
Expand Down Expand Up @@ -202,7 +201,8 @@ def __init__(self, ring, category=None):
self._ring = ring
base = ring.base_ring()
category = Algebras(base).or_subcategory(category)
Algebra.__init__(self, base, names=ring.variable_name(), normalize=True, category=category)
Parent.__init__(self, base=base, names=ring.variable_name(),
normalize=True, category=category)

def _element_constructor_(self, *args, **kwds):
r"""
Expand Down Expand Up @@ -263,7 +263,7 @@ def _coerce_map_from_(self, P):
if isinstance(P, Parent):
return P.has_coerce_map_from(self._ring)

def _repr_(self):
def _repr_(self) -> str:
r"""
Return a string representation of this Ore function field.
Expand Down Expand Up @@ -453,9 +453,25 @@ def gen(self, n=0):
"""
return self(self._ring.gen(n))

def gens(self) -> tuple:
"""
Return the tuple of generators of ``self``.
EXAMPLES::
sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^4)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x', Frob]
sage: K = S.fraction_field()
sage: K.gens()
(x,)
"""
return (self(self._ring.gen(0)),)

parameter = gen

def gens_dict(self):
def gens_dict(self) -> dict:
r"""
Return a {name: variable} dictionary of the generators of
this Ore function field.
Expand All @@ -472,7 +488,7 @@ def gens_dict(self):
"""
return dict(zip(self.variable_names(), self.gens()))

def is_finite(self):
def is_finite(self) -> bool:
r"""
Return ``False`` since Ore function field are not finite.
Expand All @@ -490,7 +506,7 @@ def is_finite(self):
"""
return False

def is_exact(self):
def is_exact(self) -> bool:
r"""
Return ``True`` if elements of this Ore function field are exact.
This happens if and only if elements of the base ring are exact.
Expand All @@ -515,7 +531,7 @@ def is_exact(self):
"""
return self.base_ring().is_exact()

def is_sparse(self):
def is_sparse(self) -> bool:
r"""
Return ``True`` if the elements of this Ore function field are sparsely
represented.
Expand All @@ -537,7 +553,7 @@ def is_sparse(self):
"""
return self._ring.is_sparse()

def ngens(self):
def ngens(self) -> int:
r"""
Return the number of generators of this Ore function field,
which is `1`.
Expand Down Expand Up @@ -598,7 +614,7 @@ def random_element(self, degree=2, monic=False, *args, **kwds):
denominator = self._ring.random_element(degdenom, True, *args, **kwds)
return self(numerator, denominator)

def is_commutative(self):
def is_commutative(self) -> bool:
r"""
Return ``True`` if this Ore function field is commutative, i.e. if the
twisting morphism is the identity and the twisting derivation vanishes.
Expand All @@ -619,7 +635,7 @@ def is_commutative(self):
"""
return self._ring.is_commutative()

def is_field(self, proof=False):
def is_field(self, proof=False) -> bool:
r"""
Return always ``True`` since Ore function field are (skew) fields.
Expand Down
54 changes: 36 additions & 18 deletions src/sage/rings/polynomial/ore_polynomial_ring.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
from sage.misc.lazy_import import lazy_import
from sage.rings.infinity import Infinity
from sage.structure.category_object import normalize_names
from sage.structure.parent import Parent

from sage.structure.unique_representation import UniqueRepresentation
from sage.rings.ring import Algebra
from sage.rings.integer import Integer
from sage.structure.element import Element

Expand All @@ -50,7 +50,7 @@
# Generic implementation of Ore polynomial rings
#################################################

class OrePolynomialRing(UniqueRepresentation, Algebra):
class OrePolynomialRing(UniqueRepresentation, Parent):
r"""
Construct and return the globally unique Ore polynomial ring with the
given properties and variable names.
Expand Down Expand Up @@ -423,7 +423,8 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None)
self._derivation = derivation
self._fraction_field = None
category = Algebras(base_ring).or_subcategory(category)
Algebra.__init__(self, base_ring, names=name, normalize=True, category=category)
Parent.__init__(self, base_ring, names=name,
normalize=True, category=category)

def __reduce__(self):
r"""
Expand Down Expand Up @@ -830,8 +831,6 @@ def gen(self, n=0):
x
sage: y == x
True
sage: y is x
True
sage: S.gen(0)
x
Expand All @@ -848,12 +847,28 @@ def gen(self, n=0):
IndexError: generator 1 not defined
"""
if n != 0:
raise IndexError("generator %s not defined" % n)
raise IndexError(f"generator {n} not defined")
return self.Element(self, [0, 1])

parameter = gen

def gens_dict(self):
def gens(self) -> tuple:
"""
Return the tuple of generators of ``self``.
EXAMPLES::
sage: R.<t> = QQ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x',sigma]; S
Ore Polynomial Ring in x over Univariate Polynomial Ring in t
over Rational Field twisted by t |--> t + 1
sage: S.gens()
(x,)
"""
return (self.Element(self, [0, 1]),)

def gens_dict(self) -> dict:
r"""
Return a {name: variable} dictionary of the generators of
this Ore polynomial ring.
Expand All @@ -868,7 +883,7 @@ def gens_dict(self):
"""
return dict(zip(self.variable_names(), self.gens()))

def is_finite(self):
def is_finite(self) -> bool:
r"""
Return ``False`` since Ore polynomial rings are not finite
(unless the base ring is `0`).
Expand All @@ -887,9 +902,10 @@ def is_finite(self):
R = self.base_ring()
return R.is_finite() and R.order() == 1

def is_exact(self):
def is_exact(self) -> bool:
r"""
Return ``True`` if elements of this Ore polynomial ring are exact.
This happens if and only if elements of the base ring are exact.
EXAMPLES::
Expand All @@ -912,7 +928,7 @@ def is_exact(self):
"""
return self.base_ring().is_exact()

def is_sparse(self):
def is_sparse(self) -> bool:
r"""
Return ``True`` if the elements of this Ore polynomial ring are
sparsely represented.
Expand All @@ -932,10 +948,11 @@ def is_sparse(self):
"""
return self.__is_sparse

def ngens(self):
def ngens(self) -> int:
r"""
Return the number of generators of this Ore polynomial ring,
which is `1`.
Return the number of generators of this Ore polynomial ring.
This is `1`.
EXAMPLES::
Expand Down Expand Up @@ -998,7 +1015,7 @@ def random_element(self, degree=(-1, 2), monic=False, *args, **kwds):
TESTS:
If the first tuple element is greater than the second, a
``ValueError`` is raised::
:class:`ValueError` is raised::
sage: S.random_element(degree=(5,4)) # needs sage.rings.finite_rings
Traceback (most recent call last):
Expand Down Expand Up @@ -1081,8 +1098,10 @@ def random_irreducible(self, degree=2, monic=True, *args, **kwds):

def is_commutative(self) -> bool:
r"""
Return ``True`` if this Ore polynomial ring is commutative, i.e. if the
twisting morphism is the identity and the twisting derivation vanishes.
Return ``True`` if this Ore polynomial ring is commutative.
This holds if the twisting morphism is the identity and the
twisting derivation vanishes.
EXAMPLES::
Expand All @@ -1109,8 +1128,7 @@ def is_commutative(self) -> bool:

def is_field(self, proof=False) -> bool:
r"""
Return always ``False`` since Ore polynomial rings are never
fields.
Return always ``False`` since Ore polynomial rings are never fields.
EXAMPLES::
Expand Down
28 changes: 0 additions & 28 deletions src/sage/rings/ring.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -1074,34 +1074,6 @@ cdef class Ring(ParentWithGens):
"""
return self(randint(-bound,bound))

def _random_nonzero_element(self, *args, **kwds):
"""
Returns a random non-zero element in this ring.
The default behaviour of this method is to repeatedly call the
``random_element`` method until a non-zero element is obtained.
In this implementation, all parameters are simply pushed forward
to the ``random_element`` method.
INPUT:
- ``*args``, ``**kwds`` - Parameters that can be forwarded to
the ``random_element`` method
OUTPUT:
- Random non-zero element
EXAMPLES::
sage: ZZ._random_nonzero_element() != 0
True
"""
while True:
x = self.random_element(*args, **kwds)
if not x.is_zero():
return x

def ideal_monoid(self):
"""
Return the monoid of ideals of this ring.
Expand Down

0 comments on commit e03f1b8

Please sign in to comment.