Skip to content

Commit

Permalink
Trac #29629: Ore polynomials
Browse files Browse the repository at this point in the history
We implement general univariate Ore polynomials (allowing for
derivations and twisted derivations)

URL: https://trac.sagemath.org/29629
Reported by: caruso
Ticket author(s): Xavier Caruso
Reviewer(s): Travis Scrimshaw
  • Loading branch information
Release Manager committed Jul 11, 2020
2 parents cd041d1 + 1c7a67c commit ee54283
Show file tree
Hide file tree
Showing 13 changed files with 4,883 additions and 4,169 deletions.
9 changes: 6 additions & 3 deletions src/doc/en/reference/polynomial_rings/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,18 @@ Multivariate Polynomials
invariant_theory
polynomial_rings_toy_implementations

Skew Polynomials
----------------
Ore Polynomials
---------------

.. toctree::
:maxdepth: 2

sage/rings/polynomial/skew_polynomial_element
sage/rings/polynomial/ore_polynomial_ring
sage/rings/polynomial/ore_polynomial_element
sage/rings/polynomial/skew_polynomial_ring
sage/rings/polynomial/skew_polynomial_element
sage/rings/polynomial/skew_polynomial_finite_order
sage/rings/polynomial/skew_polynomial_finite_field

Rational Functions
------------------
Expand Down
3 changes: 3 additions & 0 deletions src/module_list.py
Original file line number Diff line number Diff line change
Expand Up @@ -1110,6 +1110,9 @@
Extension('sage.rings.polynomial.symmetric_reduction',
sources = ['sage/rings/polynomial/symmetric_reduction.pyx']),

Extension('sage.rings.polynomial.ore_polynomial_element',
sources = ['sage/rings/polynomial/ore_polynomial_element.pyx']),

Extension('sage.rings.polynomial.skew_polynomial_element',
sources = ['sage/rings/polynomial/skew_polynomial_element.pyx']),

Expand Down
18 changes: 12 additions & 6 deletions src/sage/categories/rings.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,12 +926,17 @@ def __getitem__(self, arg):
sage: GF(17)['a']['b']
Univariate Polynomial Ring in b over Univariate Polynomial Ring in a over Finite Field of size 17
We can create skew polynomial rings::
We can create Ore polynomial rings::
sage: k.<t> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: k['x',Frob]
Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5
sage: k['x', Frob]
Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5
sage: R.<t> = QQ[]
sage: der = R.derivation()
sage: R['d', der]
Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt
We can also create power series rings by using double brackets::
Expand Down Expand Up @@ -1080,9 +1085,10 @@ def normalize_arg(arg):

if isinstance(arg, tuple):
from sage.categories.morphism import Morphism
if len(arg) == 2 and isinstance(arg[1], Morphism):
from sage.rings.polynomial.skew_polynomial_ring import SkewPolynomialRing
return SkewPolynomialRing(self, arg[1], names=arg[0])
from sage.rings.derivation import RingDerivation
if len(arg) == 2 and isinstance(arg[1], (Morphism, RingDerivation)):
from sage.rings.polynomial.ore_polynomial_ring import OrePolynomialRing
return OrePolynomialRing(self, arg[1], names=arg[0])

# 2. Otherwise, if all specified elements are algebraic, try to
# return an algebraic extension
Expand Down
110 changes: 105 additions & 5 deletions src/sage/rings/derivation.py
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,9 @@
from sage.categories.lie_algebras import LieAlgebras

from sage.categories.map import Map
from sage.categories.all import Rings
from sage.categories.rings import Rings

from sage.misc.latex import latex


class RingDerivationModule(Module, UniqueRepresentation):
Expand Down Expand Up @@ -473,7 +475,6 @@ def _repr_(self):
sage: R.derivation_module(twist=theta)
Module of twisted derivations over Multivariate Polynomial Ring in x, y
over Integer Ring (twisting morphism: x |--> y, y |--> x)
"""
t = ""
if self._twist is None:
Expand Down Expand Up @@ -850,7 +851,6 @@ def _repr_(self):
d/dx
sage: R.derivation(y)
d/dy
"""
parent = self.parent()
try:
Expand Down Expand Up @@ -884,6 +884,56 @@ def _repr_(self):
else:
return s

def _latex_(self):
r"""
Return a LaTeX representation of this derivation.
EXAMPLES::
sage: R.<x,y> = ZZ[]
sage: ddx = R.derivation(x)
sage: ddy = R.derivation(y)
sage: latex(ddx)
\frac{d}{dx}
sage: latex(ddy)
\frac{d}{dy}
sage: latex(ddx + ddy)
\frac{d}{dx} + \frac{d}{dy}
"""
parent = self.parent()
try:
dual_basis = parent.dual_basis()
except NotImplementedError:
return "\\text{A derivation on } %s" % latex(parent.domain())
coeffs = self.list()
s = ""
for i in range(len(dual_basis)):
c = coeffs[i]
sc = str(c)
if sc == "0":
continue
ddx = "\\frac{d}{d%s}" % latex(dual_basis[i])
if sc == "1":
s += " + " + ddx
elif sc == "-1":
s += " - " + ddx
elif c._is_atomic() and sc[0] != "-":
s += " + %s %s" % (sc, ddx)
elif (-c)._is_atomic():
s += " - %s %s" % (-c, ddx)
else:
s += " + \\left(%s\\right) %s" % (sc, ddx)
if s[:3] == " + ":
return s[3:]
elif s[:3] == " - ":
return "-" + s[3:]
elif s == "":
return "0"
else:
return s


def list(self):
"""
Return the list of coefficient of this derivation
Expand Down Expand Up @@ -1268,7 +1318,18 @@ def _repr_(self):
sage: M = ZZ.derivation_module()
sage: M()
0
"""
return "0"

def _latex_(self):
"""
Return a string representation of this derivation.
EXAMPLES::
sage: M = ZZ.derivation_module()
sage: latex(M())
0
"""
return "0"

Expand Down Expand Up @@ -1911,7 +1972,6 @@ def _repr_(self):
sage: theta = R.hom([y,x])
sage: R.derivation(1, twist=theta)
[x |--> y, y |--> x] - id
"""
scalar = self._scalar
sc = str(scalar)
Expand Down Expand Up @@ -1942,6 +2002,47 @@ def _repr_(self):
s = "(%s)*" % sc
return "%s(%s - %s)" % (s, stwi, sdef)

def _latex_(self):
r"""
Return a LaTeX representation of this derivation.
EXAMPLES::
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: der = k.derivation(a+1, twist=Frob)
sage: latex(der)
\left(a + 1\right) \left(\left[a \mapsto a^{5}\right] - \text{id}\right)
"""
scalar = self._scalar
sc = str(scalar)
if sc == "0":
return "0"
defining_morphism = self.parent().defining_morphism()
twisting_morphism = self.parent().twisting_morphism()
try:
if defining_morphism.is_identity():
sdef = "\\text{id}"
else:
sdef = "\\left[%s\\right]" % latex(defining_morphism)
except (AttributeError, NotImplementedError):
sdef = "\\text{defining morphism}"
try:
stwi = "\\left[%s\\right]" % latex(twisting_morphism)
except AttributeError:
stwi = "\\text{twisting morphism}"
if sc == "1":
return "%s - %s" % (stwi, sdef)
elif sc == "-1":
s = "-"
elif scalar._is_atomic():
s = "%s " % sc
elif (-scalar)._is_atomic():
s = "-%s " % (-scalar)
else:
s = "\\left(%s\\right) " % sc
return "%s \\left(%s - %s\\right)" % (s, stwi, sdef)

def _add_(self, other):
"""
Return the sum of this derivation and ``other``.
Expand Down Expand Up @@ -2173,4 +2274,3 @@ def _richcmp_(self, other, op):
else:
return True
return NotImplemented

5 changes: 3 additions & 2 deletions src/sage/rings/polynomial/all.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,9 @@
# Infinite Polynomial Rings
from sage.rings.polynomial.infinite_polynomial_ring import InfinitePolynomialRing

# Skew Polynomial Rings
from sage.rings.polynomial.skew_polynomial_ring import SkewPolynomialRing
# Ore Polynomial Rings
lazy_import('sage.rings.polynomial.ore_polynomial_ring', 'OrePolynomialRing')
SkewPolynomialRing = OrePolynomialRing

# Evaluation of cyclotomic polynomials
from sage.rings.polynomial.cyclotomic import cyclotomic_value
Expand Down
46 changes: 46 additions & 0 deletions src/sage/rings/polynomial/ore_polynomial_element.pxd
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
from sage.structure.element cimport AlgebraElement
from sage.structure.parent cimport Parent
from sage.rings.morphism cimport Morphism
from sage.structure.element cimport RingElement
from sage.rings.polynomial.polynomial_element cimport Polynomial_generic_dense

cdef class OrePolynomial(AlgebraElement):
cdef _is_gen

cdef long _hash_c(self)
cdef OrePolynomial _new_c(self, list coeffs, Parent P, char check=*)
cpdef OrePolynomial _new_constant_poly(self, RingElement a, Parent P, char check=*)
cpdef _neg_(self)
cpdef _floordiv_(self, right)
cpdef _mod_(self, right)

cpdef bint is_zero(self)
cpdef bint is_one(self)

cdef _left_quo_rem(self, OrePolynomial other)
cdef _right_quo_rem(self, OrePolynomial other)
cdef OrePolynomial _left_lcm_cofactor(self, OrePolynomial other)
cdef OrePolynomial _right_lcm_cofactor(self, OrePolynomial other)

# Abstract methods
cpdef int degree(self)
cpdef list coefficients(self, sparse=*)


cdef void lmul_gen(list A, Morphism m, d)

cdef class OrePolynomial_generic_dense(OrePolynomial):
cdef list _coeffs

cdef void __normalize(self)
cpdef _add_(self, other)
cdef list _mul_list(self, list A)
cpdef _mul_(self, other)

cpdef dict dict(self)
cpdef list list(self, bint copy=*)


cdef class OrePolynomialBaseringInjection(Morphism):
cdef RingElement _an_element
cdef object _new_constant_poly_
Loading

0 comments on commit ee54283

Please sign in to comment.