diff --git a/src/sage/rings/polynomial/ore_polynomial_element.pyx b/src/sage/rings/polynomial/ore_polynomial_element.pyx index d3c9e0cd7d1..df6f849ce68 100644 --- a/src/sage/rings/polynomial/ore_polynomial_element.pyx +++ b/src/sage/rings/polynomial/ore_polynomial_element.pyx @@ -1,56 +1,27 @@ r""" -Univariate Skew Polynomials +Univariate Ore Polynomials This module provides the :class:`~sage.rings.polynomial.skew_polynomial_element.OrePolynomial`, -which constructs a single univariate skew polynomial over commutative -base rings and an automorphism over the base ring. Skew polynomials are -non-commutative and so principal methods such as gcd, lcm, monic, -multiplication, and division are given in left and right forms. +which constructs a single univariate Ore polynomial over a commutative +base equipped with an endomorphism and/or a derivation. +It provides generic implementation of standard arithmetical operations +on Ore polynomials as addition, multiplication, gcd, lcm, etc. -The generic implementation of dense skew polynomials is -:class:`~sage.rings.polynomial.skew_polynomial_element.OrePolynomial_generic_dense`. +The generic implementation of dense Ore polynomials is +:class:`~sage.rings.polynomial.ore_polynomial_element.OrePolynomial_generic_dense`. The classes -:class:`~sage.rings.polynomial.skew_polynomial_element.ConstantOrePolynomialSection` -and :class:`~sage.rings.polynomial.skew_polynomial_element.OrePolynomialBaseringInjection` -handle conversion from a skew polynomial ring to its base ring and vice versa respectively. - -.. WARNING:: - - The current semantics of - :meth:`~sage.rings.polynomial.skew_polynomial_element.OrePolynomial.__call__` - are experimental, so a warning is thrown when a skew polynomial is evaluated - for the first time in a session. See the method documentation for details. - - TESTS:: - - sage: R. = QQ[] - sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] - sage: a = 2*(t + x) + 1 - sage: a(t^2) - doctest:...: FutureWarning: This class/method/function is marked as - experimental. It, its functionality or its interface might change - without a formal deprecation. - See http://trac.sagemath.org/13215 for details. - 2*t^3 + 3*t^2 + 4*t + 2 - sage: a(t) - 2*t^2 + 3*t + 2 +:class:`~sage.rings.polynomial.ore_polynomial_element.ConstantOrePolynomialSection` +and :class:`~sage.rings.polynomial.ore_polynomial_element.OrePolynomialBaseringInjection` +handle conversion from a Ore polynomial ring to its base ring and vice versa. AUTHORS: -- Xavier Caruso (2012-06-29): initial version - -- Arpit Merchant (2016-08-04): improved docstrings, fixed doctests and - refactored classes and methods - -- Johan Rosenkilde (2016-08-03): changes for bug fixes, docstring and - doctest errors - +- Xavier Caruso (2020-05) """ ############################################################################# -# Copyright (C) 2012 Xavier Caruso +# Copyright (C) 2020 Xavier Caruso # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -81,15 +52,16 @@ from sage.misc.superseded import experimental cdef class OrePolynomial(AlgebraElement): r""" - Abstract base class for skew polynomials. + Abstract base class for Ore polynomials. This class must be inherited from and have key methods overridden. .. RUBRIC:: Definition - Let `R` be a commutative ring equipped with an automorphism `\sigma`. + Let `R` be a commutative ring equipped with an automorphism `\sigma` + and a `\sigma`-derivation `\partial`. - Then, a skew polynomial is given by the equation: + A Ore polynomial is given by the equation: .. MATH:: @@ -97,13 +69,13 @@ cdef class OrePolynomial(AlgebraElement): where the coefficients `a_i \in R` and `X` is a formal variable. - Addition between two skew polynomials is defined by the usual addition + Addition between two Ore polynomials is defined by the usual addition operation and the modified multiplication is defined by the rule - `X a = \sigma(a) X` for all `a` in `R`. Skew polynomials are thus - non-commutative and the degree of a product is equal to the sum of the - degrees of the factors. + `X a = \sigma(a) X + \partial(a)` for all `a` in `R`. + Ore polynomials are thus non-commutative and the degree of a product + is equal to the sum of the degrees of the factors. - Let `a` and `b` be two skew polynomials in the same ring `S`. + Let `a` and `b` be two Ore polynomials in the same ring `S`. The *left (resp. right) euclidean division* of `a` by `b` is a couple `(q,r)` of elements in `S` such that @@ -121,30 +93,18 @@ cdef class OrePolynomial(AlgebraElement): in the *right* euclidean division exist and are unique. The same result holds for the *left* euclidean division if in addition - the twist map defining the skew polynomial ring is invertible. - - .. RUBRIC:: Evaluation - - The value of a given a skew polynomial `p(x) = \sum_{i=0}^d a_i x^i` - at `r` is calculated using the formula: - - .. MATH:: - - p(r) = \sum_{i=0}^d a_i \sigma^i(r) - - where `\sigma` is the base ring automorphism. This is called - the *operator evaluation* method. + the twisting morphism defining the Ore polynomial ring is invertible. EXAMPLES: We illustrate some functionalities implemented in this class. - We create the skew polynomial ring:: + We create the Ore polynomial ring (here the derivation is zero):: sage: R. = ZZ[] sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma]; S - Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 and some elements in it:: @@ -176,7 +136,7 @@ cdef class OrePolynomial(AlgebraElement): sage: b^2 == b*b True - Sage also implements arithmetic over skew polynomial rings. You will find + Sage also implements arithmetic over Ore polynomial rings. You will find below a short panorama:: sage: q,r = c.right_quo_rem(b) @@ -196,12 +156,12 @@ cdef class OrePolynomial(AlgebraElement): True Left euclidean division won't work over our current `S` because Sage can't - invert the twist map:: + invert the twisting morphism:: sage: q,r = c.left_quo_rem(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twist map Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + NotImplementedError: inversion of the twisting morphism Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring Defn: t |--> t + 1 Here we can see the effect of the operator evaluation compared to the usual @@ -209,6 +169,9 @@ cdef class OrePolynomial(AlgebraElement): sage: a = x^2 sage: a(t) + doctest:...: FutureWarning: This class/method/function is marked as experimental. + It, its functionality or its interface might change without a formal deprecation. + See http://trac.sagemath.org/13215 for details. t + 2 Here is a working example over a finite field:: @@ -236,8 +199,8 @@ cdef class OrePolynomial(AlgebraElement): sage: a.left_gcd(b) x + t - The left lcm has the following meaning: given skew polynomials `a` and `b`, - their left lcm is the least degree polynomial `c = ua = vb` for some skew + The left lcm has the following meaning: given Ore polynomials `a` and `b`, + their left lcm is the least degree polynomial `c = ua = vb` for some Ore polynomials `u, v`. Such a `c` always exist if the base ring is a field:: sage: c = a.left_lcm(b); c @@ -259,8 +222,7 @@ cdef class OrePolynomial(AlgebraElement): .. SEEALSO:: - - :mod:`sage.rings.polynomial.skew_polynomial_ring` - - :mod:`sage.rings.polynomial.skew_polynomial_ring_constructor` + - :mod:`sage.rings.polynomial.ore_polynomial_ring` """ def __init__(self, parent, construct=False): r""" @@ -306,7 +268,7 @@ cdef class OrePolynomial(AlgebraElement): r""" Return the degree of ``self``. - By convention, the zero skew polynomial has degree `-1`. + By convention, the zero Ore polynomial has degree `-1`. EXAMPLES:: @@ -324,7 +286,7 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial _new_c(self, list coeffs, Parent P, char check=0): r""" - Fast creation of a new skew polynomial + Fast creation of a new Ore polynomial .. NOTE:: @@ -335,18 +297,18 @@ cdef class OrePolynomial(AlgebraElement): cpdef OrePolynomial _new_constant_poly(self, RingElement a, Parent P, char check=0): r""" - Fast creation of a new constant skew polynomial + Fast creation of a new constant Ore polynomial EXAMPLES:: - sage: from sage.rings.polynomial.skew_polynomial_element import OrePolynomialBaseringInjection + sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x',Frob] sage: OrePolynomialBaseringInjection(k, k['x', Frob]) #indirect doctest - Skew Polynomial base injection morphism: + Ore Polynomial base injection morphism: From: Finite Field in t of size 5^3 - To: Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + To: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 """ if a: n = self._new_c([a],P,check) @@ -370,9 +332,9 @@ cdef class OrePolynomial(AlgebraElement): sage: a[1] = t + 1 Traceback (most recent call last): ... - IndexError: skew polynomials are immutable + IndexError: Ore polynomials are immutable """ - raise IndexError("skew polynomials are immutable") + raise IndexError("Ore polynomials are immutable") def square(self): r""" @@ -382,13 +344,18 @@ cdef class OrePolynomial(AlgebraElement): sage: R. = QQ[] sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] + sage: S. = R['x', sigma] sage: a = x + t; a x + t sage: a.square() x^2 + (2*t + 1)*x + t^2 sage: a.square() == a*a True + + sage: der = R.derivation() + sage: A. = R['d', der] + sage: (d + t).square() + d^2 + 2*t*d + t^2 + 1 """ return self * self @@ -426,14 +393,14 @@ cdef class OrePolynomial(AlgebraElement): """ cdef int d = self.degree() if d == -1: - raise ValueError("the skew polynomial must not be 0") + raise ValueError("the Ore polynomial must not be 0") return self[d] def is_unit(self): r""" - Return ``True`` if this skew polynomial is a unit. + Return ``True`` if this Ore polynomial is a unit. - When the base ring `R` is an integral domain, then a skew polynomial `f` + When the base ring `R` is an integral domain, then a Ore polynomial `f` is a unit if and only if degree of `f` is `0` and `f` is then a unit in `R`. @@ -459,22 +426,18 @@ cdef class OrePolynomial(AlgebraElement): else: return False else: - raise NotImplementedError("is_unit is not implemented for skew polynomial rings " + raise NotImplementedError("is_unit is not implemented for Ore polynomial rings " "over base rings which are not integral domains.") def is_nilpotent(self): r""" Check if ``self`` is nilpotent. - Given a commutative ring `R` and a base ring automorphism `\sigma` - of order `n`, an element `f` of `R[X, \sigma]` is nilpotent if - and only if all coefficients of `f^n` are nilpotent in `R`. - .. NOTE:: The paper "Nilpotents and units in skew polynomial rings over commutative rings" by M. Rimmer and K.R. Pearson describes - the method to check whether a given skew polynomial is nilpotent. + a method to check whether a given skew polynomial is nilpotent. That method however, requires one to know the order of the automorphism which is not available in Sage. This method is thus not yet implemented. @@ -493,7 +456,7 @@ cdef class OrePolynomial(AlgebraElement): def is_monic(self): r""" - Return ``True`` if this skew polynomial is monic. + Return ``True`` if this Ore polynomial is monic. The zero polynomial is by definition not monic. @@ -519,12 +482,12 @@ cdef class OrePolynomial(AlgebraElement): def left_monic(self): r""" - Return the unique monic skew polynomial `m` which divides ``self`` on - the left and has the same degree. + Return the unique monic Ore polynomial `m` which divides this + polynomial on the left and has the same degree. - Given a skew polynomial `p` of degree `n`, its left monic is given by - `m = p \sigma^{-n}(1/k)`, where `k` is the leading coefficient of - `p`, i.e. by the appropriate scalar multiplication on the right. + Given a Ore polynomial `P` of degree `n`, its left monic is given by + `P \cdot \sigma^{-n}(1/k)`, where `k` is the leading coefficient of + `P` and `\sigma` is the twisting morphism. EXAMPLES:: @@ -541,7 +504,7 @@ cdef class OrePolynomial(AlgebraElement): True sage: b.is_left_divisible_by(a) True - sage: twist = S.twist_map(-a.degree()) + sage: twist = S.twisting_morphism(-a.degree()) sage: a == b * twist(a.leading_coefficient()) True @@ -554,8 +517,8 @@ cdef class OrePolynomial(AlgebraElement): unit:: sage: R. = QQ[] - sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] + sage: der = R.derivation() + sage: S. = R['x', der] sage: a = t*x sage: a.left_monic() Traceback (most recent call last): @@ -575,12 +538,11 @@ cdef class OrePolynomial(AlgebraElement): def right_monic(self): r""" - Return the unique monic skew polynomial `m` which divides ``self`` on - the right and has the same degree. + Return the unique monic Ore polynomial which divides this polynomial + on the right and has the same degree. - Given a skew polynomial `p` of degree `n`, its left monic is given by - `m = (1/k) * p`, where `k` is the leading coefficient of `p`, i.e. by - the appropriate scalar multiplication on the left. + Given a Ore polynomial `P` of degree `n`, its left monic is given by + `(1/k) \cdot P`, where `k` is the leading coefficient of `p`. EXAMPLES:: @@ -609,8 +571,8 @@ cdef class OrePolynomial(AlgebraElement): unit:: sage: R. = QQ[] - sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] + sage: der = R.derivation() + sage: S. = R['x', der] sage: a = t*x sage: a.right_monic() Traceback (most recent call last): @@ -710,7 +672,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` OUTPUT: @@ -745,7 +707,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` OUTPUT: @@ -794,7 +756,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` OUTPUT: @@ -829,7 +791,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` OUTPUT: @@ -878,27 +840,27 @@ cdef class OrePolynomial(AlgebraElement): Return the left gcd of ``self`` and ``other`` along with the coefficients for the linear combination. - If `a` is ``self`` and `b` is ``other``, then there are skew polynomials + If `a` is ``self`` and `b` is ``other``, then there are Ore polynomials `u` and `v` such that `g = a u + b v`, where `g` is the left gcd of `a` and `b`. This method returns `(g, u, v)`. INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``). Return whether the left gcd should be normalized to be monic. OUTPUT: - - The left gcd of ``self`` and ``other``, that is a skew polynomial - `g` with the following property: any skew polynomial is + - The left gcd of ``self`` and ``other``, that is a Ore polynomial + `g` with the following property: any Ore polynomial is divisible on the left by `g` iff it is divisible on the left by both ``self`` and ``other``. If monic is ``True``, `g` is in addition monic. (With this extra condition, it is uniquely determined.) - - Two skew polynomials `u` and `v` such that: + - Two Ore polynomials `u` and `v` such that: .. MATH:: @@ -910,8 +872,8 @@ cdef class OrePolynomial(AlgebraElement): Works only if following two conditions are fulfilled (otherwise left gcd do not exist in general): - 1) the base ring is a field and 2) the twist map on - this field is bijective. + 1) the base ring is a field and + 2) the twisting morphism is bijective. EXAMPLES:: @@ -944,7 +906,7 @@ cdef class OrePolynomial(AlgebraElement): ... TypeError: the base ring must be a field - And the twist map must be bijective:: + And the twisting morphism must be bijective:: sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) @@ -954,7 +916,7 @@ cdef class OrePolynomial(AlgebraElement): sage: a.left_xgcd(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twist map Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in Fields: @@ -1004,17 +966,17 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` OUTPUT: - the quotient and the remainder of the left euclidean - division of this skew polynomial by ``other`` + division of this Ore polynomial by ``other`` .. NOTE:: This will fail if the leading coefficient of ``other`` is not a unit - or if Sage can't invert the twist map. + or if Sage can't invert the twisting morphism. EXAMPLES:: @@ -1028,7 +990,7 @@ cdef class OrePolynomial(AlgebraElement): True In the following example, Sage does not know the inverse - of the twist map:: + of the twisting morphism:: sage: R. = ZZ[] sage: sigma = R.hom([t+1]) @@ -1038,7 +1000,7 @@ cdef class OrePolynomial(AlgebraElement): sage: a.left_quo_rem(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twist map Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring + NotImplementedError: inversion of the twisting morphism Ring endomorphism of Univariate Polynomial Ring in t over Integer Ring Defn: t |--> t + 1 """ if not other: @@ -1062,12 +1024,12 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` OUTPUT: - the quotient and the remainder of the left euclidean - division of this skew polynomial by ``other`` + division of this Ore polynomial by ``other`` .. NOTE:: @@ -1106,27 +1068,27 @@ cdef class OrePolynomial(AlgebraElement): Return the right gcd of ``self`` and ``other`` along with the coefficients for the linear combination. - If `a` is ``self`` and `b` is ``other``, then there are skew polynomials + If `a` is ``self`` and `b` is ``other``, then there are Ore polynomials `u` and `v` such that `g = u a + v b`, where `g` is the right gcd of `a` and `b`. This method returns `(g, u, v)`. INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``). Return whether the right gcd should be normalized to be monic. OUTPUT: - - The right gcd of ``self`` and ``other``, that is a skew polynomial - `g` with the following property: any skew polynomial is + - The right gcd of ``self`` and ``other``, that is a Ore polynomial + `g` with the following property: any Ore polynomial is divisible on the right by `g` iff it is divisible on the right by both ``self`` and ``other``. If monic is ``True``, `g` is in addition monic. (With this extra condition, it is uniquely determined.) - - Two skew polynomials `u` and `v` such that: + - Two Ore polynomials `u` and `v` such that: .. MATH:: @@ -1203,15 +1165,15 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``). Return whether the right gcd should be normalized to be monic. OUTPUT: - The right gcd of ``self`` and ``other``, that is a skew polynomial - `g` with the following property: any skew polynomial is + The right gcd of ``self`` and ``other``, that is a Ore polynomial + `g` with the following property: any Ore polynomial is divisible on the right by `g` iff it is divisible on the right by both ``self`` and ``other``. If monic is ``True``, `g` is in addition monic. (With this @@ -1268,15 +1230,15 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``). Return whether the left gcd should be normalized to be monic. OUTPUT: - The left gcd of ``self`` and ``other``, that is a skew polynomial - `g` with the following property: any skew polynomial is + The left gcd of ``self`` and ``other``, that is a Ore polynomial + `g` with the following property: any Ore polynomial is divisible on the left by `g` iff it is divisible on the left by both ``self`` and ``other``. If monic is ``True``, `g` is in addition monic. (With this @@ -1284,10 +1246,10 @@ cdef class OrePolynomial(AlgebraElement): .. NOTE:: - Works only if two following conditions are fulfilled + Works only if following two conditions are fulfilled (otherwise left gcd do not exist in general): - 1) the base ring is a field and 2) the twist map on - this field is bijective. + 1) the base ring is a field and + 2) the twisting morphism is bijective. EXAMPLES:: @@ -1316,7 +1278,7 @@ cdef class OrePolynomial(AlgebraElement): ... TypeError: the base ring must be a field - And the twist map needs to be bijective:: + And the twisting morphism needs to be bijective:: sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) @@ -1326,7 +1288,7 @@ cdef class OrePolynomial(AlgebraElement): sage: a.left_gcd(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twist map Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in Fields: @@ -1345,15 +1307,15 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial _left_lcm_cofactor(self, OrePolynomial other): r""" - Return a skew polynomial `U` such that `U P = c L` - where `P` is this skew polynomial (``self``), `L` + Return a Ore polynomial `U` such that `U P = c L` + where `P` is this Ore polynomial (``self``), `L` is the left lcm of `P` and ``other`` and `c` is a constant TESTS:: sage: cython(''' - ....: from sage.rings.polynomial.skew_polynomial_element cimport OrePolynomial + ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def left_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._left_lcm_cofactor(Q) ....: ''') @@ -1386,7 +1348,7 @@ cdef class OrePolynomial(AlgebraElement): def left_xlcm(self, other, monic=True): r""" Return the left lcm `L` of ``self`` and ``other`` together - with two skew polynomials `U` and `V` such that + with two Ore polynomials `U` and `V` such that .. MATH:: @@ -1422,15 +1384,15 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial _right_lcm_cofactor(self, OrePolynomial other): r""" - Return a skew polynomial `U` such that `P U = L c` - where `P` is this skew polynomial (``self``), `L` + Return a Ore polynomial `U` such that `P U = L c` + where `P` is this Ore polynomial (``self``), `L` is the right lcm of `P` and ``other`` and `c` is a constant TESTS:: sage: cython(''' - ....: from sage.rings.polynomial.skew_polynomial_element cimport OrePolynomial + ....: from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial ....: def right_lcm_cofactor(OrePolynomial P, OrePolynomial Q): ....: return P._right_lcm_cofactor(Q) ....: ''') @@ -1463,7 +1425,7 @@ cdef class OrePolynomial(AlgebraElement): def right_xlcm(self, other, monic=True): r""" Return the right lcm `L` of ``self`` and ``other`` together - with two skew polynomials `U` and `V` such that + with two Ore polynomials `U` and `V` such that .. MATH:: @@ -1471,7 +1433,7 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- a boolean (default: ``True``); whether the right lcm should be normalized to be monic @@ -1499,7 +1461,7 @@ cdef class OrePolynomial(AlgebraElement): cdef OrePolynomial L = self * V1 if monic: s = self.base_ring()(~L.leading_coefficient()) - s = self._parent.twist_map(-L.degree())(s) + s = self._parent.twisting_morphism(-L.degree())(s) L = L * s V1 = V1 * s W1, _ = L._left_quo_rem(other) @@ -1513,15 +1475,15 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``). Return whether the left lcm should be normalized to be monic. OUTPUT: - The left lcm of ``self`` and ``other``, that is a skew polynomial - `g` with the following property: any skew polynomial divides + The left lcm of ``self`` and ``other``, that is a Ore polynomial + `g` with the following property: any Ore polynomial divides `g` on the *right* iff it divides both ``self`` and ``other`` on the *right*. If monic is ``True``, `g` is in addition monic. (With this @@ -1581,15 +1543,15 @@ cdef class OrePolynomial(AlgebraElement): INPUT: - - ``other`` -- a skew polynomial in the same ring as ``self`` + - ``other`` -- a Ore polynomial in the same ring as ``self`` - ``monic`` -- boolean (default: ``True``). Return whether the right lcm should be normalized to be monic. OUTPUT: - The right lcm of ``self`` and ``other``, that is a skew polynomial - `g` with the following property: any skew polynomial divides + The right lcm of ``self`` and ``other``, that is a Ore polynomial + `g` with the following property: any Ore polynomial divides `g` on the *left* iff it divides both ``self`` and ``other`` on the *left*. If monic is ``True``, `g` is in addition monic. (With this @@ -1599,7 +1561,7 @@ cdef class OrePolynomial(AlgebraElement): Works only if two following conditions are fulfilled (otherwise right lcm do not exist in general): - 1) the base ring is a field and 2) the twist map on + 1) the base ring is a field and 2) the twisting morphism on this field is bijective. EXAMPLES:: @@ -1636,7 +1598,7 @@ cdef class OrePolynomial(AlgebraElement): ... TypeError: the base ring must be a field - And the twist map needs to be bijective:: + And the twisting morphism needs to be bijective:: sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) @@ -1646,7 +1608,7 @@ cdef class OrePolynomial(AlgebraElement): sage: a.right_lcm(b) Traceback (most recent call last): ... - NotImplementedError: inversion of the twist map Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field + NotImplementedError: inversion of the twisting morphism Ring endomorphism of Fraction Field of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t^2 """ if self.base_ring() not in Fields: @@ -1660,12 +1622,12 @@ cdef class OrePolynomial(AlgebraElement): def _repr_(self, name=None): r""" - Return string representation of this skew polynomial. + Return string representation of this Ore polynomial. INPUT: - ``name`` -- the name of the variable (default: the - name given when the skew polynomial ring was created) + name given when the Ore polynomial ring was created) EXAMPLES:: @@ -1710,12 +1672,12 @@ cdef class OrePolynomial(AlgebraElement): def _latex_(self, name=None): r""" - Return a latex representation of this skew polynomial. + Return a latex representation of this Ore polynomial. INPUT: - ``name`` -- the name of the variable (default: the - name given when the skew polynomial ring was created) + name given when the Ore polynomial ring was created) EXAMPLES:: @@ -1886,9 +1848,9 @@ cdef class OrePolynomial(AlgebraElement): r""" Change the name of the variable of ``self``. - This will create the skew polynomial ring with the new name but same - base ring and twist map. The returned skew polynomial will be an element - of that skew polynomial ring. + This will create the Ore polynomial ring with the new name but same + base ring, twisting morphism and twisting derivation. The returned + Ore polynomial will be an element of that Ore polynomial ring. INPUT: @@ -1906,7 +1868,7 @@ cdef class OrePolynomial(AlgebraElement): Note that a new parent is created at the same time:: sage: b.parent() - Skew Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring + Ore Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 """ R = self._parent.change_var(var) @@ -2027,7 +1989,7 @@ cdef class OrePolynomial(AlgebraElement): r""" Return a "copy" of ``self``. - In Sage, since skew polynomials are immutable, this just returns + In Sage, since Ore polynomials are immutable, this just returns ``self`` again. EXAMPLES:: @@ -2224,7 +2186,19 @@ cdef class OrePolynomial(AlgebraElement): cdef void lmul_gen(list A, Morphism m, d): r""" - Helper function + If ``A`` is the list of coefficients of a Ore polynomial ``P``, + replace it by the list of coefficients of ``X*P`` (where ``X`` + is the variable in the Ore polynomial ring). + + This is an helper function. + + INPUT: + + - ``A`` -- a list of coefficients + + - ``m`` -- the twisting morphism of the Ore polynomial ring + + - ``d`` -- the twisting derivation of the Ore polynomial ring """ if m is None: A.append(A[-1]) @@ -2238,12 +2212,12 @@ cdef void lmul_gen(list A, Morphism m, d): cdef class OrePolynomial_generic_dense(OrePolynomial): r""" - Generic implementation of dense skew polynomial supporting any valid base - ring and twist map. + Generic implementation of dense Ore polynomial supporting any valid base + ring, twisting morphism and twisting derivation. """ def __init__(self, parent, x=None, int check=1, int construct=0, **kwds): r""" - Construct a skew polynomial over the given parent with the given + Construct a Ore polynomial over the given parent with the given coefficients. INPUT: @@ -2262,12 +2236,12 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma] - We create a skew polynomial from a list:: + We create a Ore polynomial from a list:: sage: S([t,1]) x + t - from another skew polynomial:: + from another Ore polynomial:: sage: S(x^2 + t) x^2 + t @@ -2327,7 +2301,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): def __reduce__(self): r""" - Return the generic dense skew polynomial corresponding to the + Return the generic dense Ore polynomial corresponding to the current parameters provided ``self``. EXAMPLES:: @@ -2375,11 +2349,11 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cdef OrePolynomial _new_c(self, list coeffs, Parent P, char check=0): r""" - Fast creation of a new skew polynomial given a list of coefficients. + Fast creation of a new Ore polynomial given a list of coefficients. .. WARNING:: - The list ``coeffs`` is stored internally in the newly created skew + The list ``coeffs`` is stored internally in the newly created Ore polynomial, so this must not be modified after calling this method. TESTS:: @@ -2408,7 +2382,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): sage: R. = QQ[] sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma]; S #indirect doctest - Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 """ cdef list x = self._coeffs cdef Py_ssize_t n = len(x) - 1 @@ -2418,7 +2392,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cpdef _richcmp_(left, right, int op): r""" - Compare the two skew polynomials ``self`` and ``other``. + Compare the two Ore polynomials ``self`` and ``other``. We order polynomials first by degree, then in dictionary order starting with the coefficient of largest degree. @@ -2536,7 +2510,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): r""" Return the degree of ``self``. - By convention, the zero skew polynomial has degree `-1`. + By convention, the zero Ore polynomial has degree `-1`. EXAMPLES:: @@ -2636,7 +2610,7 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): r""" Return the minimal degree of a non-zero monomial of ``self``. - By convention, the zero skew polynomial has valuation `+\infty`. + By convention, the zero Ore polynomial has valuation `+\infty`. EXAMPLES:: @@ -2700,19 +2674,87 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): return BA cpdef _lmul_(self, Element s): + r""" + Return the product ``self * right``. + + INPUT: + + - ``right`` -- an element of the base ring + + EXAMPLES:: + + sage: R. = QQ[] + sage: der = R.derivation() + sage: A. = R['d', der] + sage: d*t # indirect doctest + t*d + 1 + """ cdef coeffs = self._mul_list([s]) return self._new_c(coeffs, self._parent, 1) cpdef _rmul_(self, Element s): + r""" + Return the product ``left * self``. + + INPUT: + + - ``left`` -- an element of the base ring + + EXAMPLES:: + + sage: R. = QQ[] + sage: der = R.derivation() + sage: A. = R['d', der] + sage: t*(d + 1) # indirect doctest + t*d + t + """ return self._new_c([ s*c for c in self._coeffs ], self._parent) cpdef _mul_(self, other): + r""" + Return the product ``self * right``. + + INPUT: + + - ``right`` -- a Ore polynomial in the same ring as ``self`` + + EXAMPLES:: + + sage: R. = QQ[] + sage: der = R.derivation() + sage: A. = R['d', der] + sage: P = d^2 + t + sage: Q = d^2 + (t + 1)*d + sage: P * Q + d^4 + (t + 1)*d^3 + (t + 2)*d^2 + (t^2 + t)*d + sage: P * Q == Q * P + False + + TESTS:: + + We check associativity and distributivity:: + + sage: U = A.random_element(degree=10) + sage: V = A.random_element(degree=10) + sage: W = A.random_element(degree=10) + sage: U * (V * W) == (U * V) * W + True + sage: U * (V + W) == U*V + U*W + True + sage: (U + V) * W == U*W + V*W + True + """ cdef coeffs = list((other)._coeffs) if coeffs: coeffs = self._mul_list(coeffs) return self._new_c(coeffs, self._parent, 1) cdef _left_quo_rem(self, OrePolynomial other): + r""" + Return the quotient and remainder of the left euclidean + division of ``self`` by ``other`` (C implementation). + """ + sig_check() cdef list A = list(self._coeffs) cdef Py_ssize_t degB = other.degree() cdef Morphism m = self._parent.twisting_morphism(-degB) @@ -2737,6 +2779,11 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): return self._new_c(quo, self._parent), self._new_c(A[:degB], self._parent, 1) cdef _right_quo_rem(self, OrePolynomial other): + r""" + Return the quotient and remainder of the right euclidean + division of ``self`` by ``other`` (C implementation). + """ + sig_check() cdef list A = list(self._coeffs) cdef Py_ssize_t i, j cdef Py_ssize_t degB = other.degree() @@ -2796,37 +2843,37 @@ cdef class OrePolynomial_generic_dense(OrePolynomial): cdef class ConstantOrePolynomialSection(Map): r""" - Representation of the canonical homomorphism from the constants of a skew + Representation of the canonical homomorphism from the constants of a Ore polynomial ring to the base ring. - This class is necessary for automatic coercion from zero-degree skew + This class is necessary for automatic coercion from zero-degree Ore polynomial ring into the base ring. EXAMPLES:: - sage: from sage.rings.polynomial.skew_polynomial_element import ConstantOrePolynomialSection + sage: from sage.rings.polynomial.ore_polynomial_element import ConstantOrePolynomialSection sage: R. = QQ[] sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma] sage: m = ConstantOrePolynomialSection(S, R); m Generic map: - From: Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + From: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 To: Univariate Polynomial Ring in t over Rational Field """ cpdef Element _call_(self, x): r""" Return the corresponding element of the base ring if ``self`` is a - constant skew polynomial. Otherwise, it fails. + constant Ore polynomial. Otherwise, it fails. TESTS:: - sage: from sage.rings.polynomial.skew_polynomial_element import ConstantOrePolynomialSection + sage: from sage.rings.polynomial.ore_polynomial_element import ConstantOrePolynomialSection sage: R. = QQ[] sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma] sage: m = ConstantOrePolynomialSection(S, R); m Generic map: - From: Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + From: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 To: Univariate Polynomial Ring in t over Rational Field sage: m(S([0,1])-S([0,1])) 0 @@ -2848,7 +2895,7 @@ cdef class ConstantOrePolynomialSection(Map): cdef class OrePolynomialBaseringInjection(Morphism): r""" - Representation of the canonical homomorphism from a ring `R` into a skew + Representation of the canonical homomorphism from a ring `R` into a Ore polynomial ring over `R`. This class is necessary for automatic coercion from the base ring to the Ore @@ -2864,11 +2911,10 @@ cdef class OrePolynomialBaseringInjection(Morphism): sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma] sage: S.coerce_map_from(S.base_ring()) #indirect doctest - Skew Polynomial base injection morphism: + Ore Polynomial base injection morphism: From: Univariate Polynomial Ring in t over Rational Field - To: Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + To: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 """ - def __init__(self, domain, codomain): r""" Construct a Skew Polynomial Basering Injection. @@ -2877,27 +2923,27 @@ cdef class OrePolynomialBaseringInjection(Morphism): - ``domain`` -- a ring `R`. This will be the domain of the injection. - - ``codomain`` -- a skew polynomial ring over ``domain``. This will be + - ``codomain`` -- a Ore polynomial ring over ``domain``. This will be the codomain. TESTS:: - sage: from sage.rings.polynomial.skew_polynomial_element import OrePolynomialBaseringInjection + sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x',Frob] sage: OrePolynomialBaseringInjection(k, k['x', Frob]) - Skew Polynomial base injection morphism: + Ore Polynomial base injection morphism: From: Finite Field in t of size 5^3 - To: Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + To: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 sage: R. = QQ[] sage: OrePolynomialBaseringInjection(QQ, k['x', Frob]) Traceback (most recent call last): ... - AssertionError: the domain of the injection must be the base ring of the skew polynomial ring + AssertionError: the domain of the injection must be the base ring of the Ore polynomial ring """ assert codomain.base_ring() is domain, \ - "the domain of the injection must be the base ring of the skew polynomial ring" + "the domain of the injection must be the base ring of the Ore polynomial ring" Morphism.__init__(self, Hom(domain,codomain)) self._an_element = codomain.gen() self._repr_type_str = "Ore Polynomial base injection" @@ -2909,7 +2955,7 @@ cdef class OrePolynomialBaseringInjection(Morphism): EXAMPLES:: - sage: from sage.rings.polynomial.skew_polynomial_element import OrePolynomialBaseringInjection + sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x',Frob] @@ -2921,7 +2967,7 @@ cdef class OrePolynomialBaseringInjection(Morphism): cpdef Element _call_(self, e): r""" - Return the corresponding skew polynomial to the element from the + Return the corresponding Ore polynomial to the element from the base ring according to ``self``. INPUT: @@ -2930,11 +2976,11 @@ cdef class OrePolynomialBaseringInjection(Morphism): OUTPUT: - The skew polynomial corresponding to `e` according to ``self``. + The Ore polynomial corresponding to `e` according to ``self``. TESTS:: - sage: from sage.rings.polynomial.skew_polynomial_element import OrePolynomialBaseringInjection + sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x',Frob] @@ -2942,7 +2988,7 @@ cdef class OrePolynomialBaseringInjection(Morphism): sage: m(4) 4 sage: parent(m(4)) - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 """ try: return self._codomain._element_constructor_(e) @@ -2951,19 +2997,19 @@ cdef class OrePolynomialBaseringInjection(Morphism): def section(self): r""" - Return the canonical homomorphism from the constants of a skew + Return the canonical homomorphism from the constants of a Ore polynomial ring to the base ring according to ``self``. TESTS:: - sage: from sage.rings.polynomial.skew_polynomial_element import OrePolynomialBaseringInjection + sage: from sage.rings.polynomial.ore_polynomial_element import OrePolynomialBaseringInjection sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x',Frob] sage: m = OrePolynomialBaseringInjection(k, k['x', Frob]) sage: m.section() Generic map: - From: Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + From: Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 To: Finite Field in t of size 5^3 """ return ConstantOrePolynomialSection(self._codomain, self.domain()) diff --git a/src/sage/rings/polynomial/ore_polynomial_ring.py b/src/sage/rings/polynomial/ore_polynomial_ring.py index 5c968cf08da..9d97dfb5220 100644 --- a/src/sage/rings/polynomial/ore_polynomial_ring.py +++ b/src/sage/rings/polynomial/ore_polynomial_ring.py @@ -1,6 +1,10 @@ r""" Univariate Ore Polynomial Rings +This module provides the :class:`~sage.rings.polynomial.ore_polynomial_ring.OrePolynomialRing`. +which constructs a general dense univariate Ore polynomial ring over a commutative base with +equipped with an endomorphism and/or a derivation. + AUTHOR: - Xavier Caruso (2020-04) @@ -44,14 +48,249 @@ WORKING_CENTER_MAX_TRIES = 1000 -# Generic implementation of skew polynomial rings +# Generic implementation of Ore polynomial rings ################################################# class OrePolynomialRing(Algebra, UniqueRepresentation): + r""" + Construct and return the globally unique Ore polynomial ring with the + given properties and variable names. + + Given a ring `R` and a ring automorphism `\sigma` of `R` and a + `\sigma`-derivation `\partial`, the ring of Ore polynomials + `R[X; \sigma, \partial]` is the usual abelian group polynomial + `R[X]` equipped with the modification multiplication deduced from the + rule `X a = \sigma(a) X + \partial(a)`. + We refer to [Ore1933]_ for more material on Ore polynomials. + + INPUT: + + - ``base_ring`` -- a commutative ring + + - ``twisting_map`` -- either an endomorphism of the base ring, or + a (twisted) derivation of it + + - ``names`` -- a string or a list of strings + + - ``sparse`` -- a boolean (default: ``False``). Currently not supported. + + EXAMPLES: + + THE CASE OF A TWISTING ENDOMORPHISM: + + We create the Ore ring `\FF_{5^3}[x, \text{Frob}]` where Frob is the + Frobenius endomorphism. + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S = OrePolynomialRing(k, Frob, 'x') + sage: S + Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 + + In particular, observe that it is not needed to create and pass in + the twisting derivation (which is `0` in our example). + + As a shortcut, we can use the square brackets notation as follow:: + + sage: T. = k['x', Frob] + sage: T + Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 + sage: T is S + True + + We emphasize that it is necessary to repeat the name of the variable + in the right hand side. Indeed, the following fails (it is interpreted + by Sage as a classical polynomial ring with variable name ``Frob``). + + sage: T. = k[Frob] + Traceback (most recent call last): + ... + ValueError: variable name 'Frobenius endomorphism a |--> a^5 on Finite Field in a of size 5^3' is not alphanumeric + + Note moreover that, similarly to the classical case, using the brackets + notation also sets the variable:: + + sage: x.parent() is S + True + + We are now ready to carry on computations in the Ore ring:: + + sage: x*a + (2*a^2 + 4*a + 4)*x + sage: Frob(a)*x + (2*a^2 + 4*a + 4)*x + + THE CASE OF A TWISTING DERIVATION: + + We can similarly create the Ore ring of differential operators over + `\QQ[t]`, namely `\QQ[t][d, \frac{d}{dt}]`:: + + sage: R. = QQ[] + sage: der = R.derivation(); der + d/dt + sage: A = OrePolynomialRing(R, der, 'd') + sage: A + Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt + + Again, the brackets notation is available:: + + sage: B. = R['d', der] + sage: A is B + True + + and computations can be carried out:: + + sage: d*t + t*d + 1 + + THE COMBINED CASE: + + Ore polynomial rings involving at the same time a twisting morphism + `sigma` and a twisting `sigma`-derivation can be created as well as + follows:: + + sage: F. = Qq(3^2) + sage: sigma = F.frobenius_endomorphism(); sigma + Frobenius endomorphism on 3-adic Unramified Extension Field in u defined by x^2 + 2*x + 2 lifting u |--> u^3 on the residue field + sage: der = F.derivation(3, twist=sigma); der + (3 + O(3^21))*([Frob] - id) + + sage: M. = F['X', der] + sage: M + Ore Polynomial Ring in X over 3-adic Unramified Extension Field in u defined by x^2 + 2*x + 2 twisted by Frob and (3 + O(3^21))*([Frob] - id) + + We emphasize that we only need to pass in the twisted derivation as + it already contains in it the datum of the twisting endomorphism. + Actually, passing in both twisting maps results in an error:: + + sage: F['X', sigma, der] + Traceback (most recent call last): + ... + ValueError: variable name 'Frobenius endomorphism ...' is not alphanumeric + + EXAMPLES of VARIABLE NAME CONTEXT:: + + sage: R. = ZZ[] + sage: sigma = R.hom([t+1]) + sage: S. = SkewPolynomialRing(R, sigma); S + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring + twisted by t |--> t + 1 + + The names of the variables defined above cannot be arbitrarily + modified because each Ore polynomial ring is unique in Sage and other + objects in Sage could have pointers to that Ore polynomial ring. + + However, the variable can be changed within the scope of a ``with`` + block using the localvars context:: + + sage: with localvars(S, ['y']): + ....: print(S) + Ore Polynomial Ring in y over Univariate Polynomial Ring in t over Integer Ring + twisted by t |--> t + 1 + + UNIQUENESS and IMMUTABILITY: + + In Sage, there is exactly one Ore polynomial ring for each quadruple + (base ring, twisting morphism, twisting derivation, name of the variable). + + sage: k. = GF(7^3) + sage: Frob = k.frobenius_endomorphism() + sage: S = k['x', Frob] + sage: T = k['x', Frob] + sage: S is T + True + + Rings with different variables names are different:: + + sage: S is k['y', Frob] + False + + Similarly, varying the twisting morphisms yields to different Ore rings + (expect when the morphism coincide):: + + sage: S is k['x', Frob^2] + False + sage: S is k['x', Frob^3] + False + sage: S is k['x', Frob^4] + True + + TESTS: + + You must specify a variable name:: + + sage: SkewPolynomialRing(k, Frob) + Traceback (most recent call last): + ... + TypeError: you must specify the name of the variable + + Multivariate Ore polynomial rings are not supported:: + + sage: S = OrePolynomialRing(k, Frob,names=['x','y']) + Traceback (most recent call last): + ... + NotImplementedError: multivariate Ore polynomials rings not supported + + Sparse Ore polynomial rings are not implemented:: + + sage: S = SkewPolynomialRing(k, Frob, names='x', sparse=True) + Traceback (most recent call last): + ... + NotImplementedError: sparse Ore polynomial rings are not implemented + + Saving and loading of polynomial rings works:: + + sage: loads(dumps(S)) is S + True + + .. TODO:: + + - Sparse Ore Polynomial Ring + - Multivariate Ore Polynomial Ring + """ Element = None @staticmethod def __classcall_private__(cls, base_ring, twist=None, names=None, sparse=False): + r""" + Construct the Ore polynomial ring associated to the given parameters. + + TESTS:: + + sage: R. = QQ[] + sage: der = R.derivation() + sage: A. = OrePolynomialRing(R, der) + sage: A + Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt + sage: type(A) + + + We check the uniqueness property of parents:: + + sage: der2 = R.derivation() + sage: B. = SkewPolynomialRing(R, der2) + sage: A is B + True + + When there is no twisting derivation, a special class is used:: + + sage: k. = ZZ[] + sage: theta = k.hom([t+1]) + sage: S. = SkewPolynomialRing(k, theta) + sage: S + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + sage: type(S) + + + In certain situations (e.g. when the twisting morphism is the Frobenius + over a finite field), even more specialized classes are used:: + + sage: k. = GF(7^5) + sage: Frob = k.frobenius_endomorphism(2) + sage: S. = SkewPolynomialRing(k, Frob) + sage: type(S) + + """ if base_ring not in CommutativeRings(): raise TypeError('base_ring must be a commutative ring') if isinstance(twist, Morphism): @@ -73,19 +312,22 @@ def __classcall_private__(cls, base_ring, twist=None, names=None, sparse=False): else: derivation = None else: - raise TypeError("the twist map must be a ring morphism or a derivation") - if sparse: - raise NotImplementedError("sparse skew polynomial rings are not implemented") + raise TypeError("the twisting map must be a ring morphism or a derivation") if names is None: raise TypeError("you must specify the name of the variable") try: names = normalize_names(1, names)[0] except IndexError: - raise NotImplementedError("multivariate skew polynomials rings not supported") + raise NotImplementedError("multivariate Ore polynomials rings not supported") - # We find the best constructor + # If there is no twisting morphism and no twisting derivation + # we return a classical polynomial ring if derivation is None and morphism is None: - return PolynomialRing(base_ring, names, sparse) + return PolynomialRing(base_ring, names, sparse=sparse) + + # We find the best constructor + if sparse: + raise NotImplementedError("sparse Ore polynomial rings are not implemented") from sage.rings.polynomial import skew_polynomial_ring constructors = [ ] @@ -119,7 +361,9 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) - ``base_ring`` -- a commutative ring - - ``twisting_morphism`` -- an automorphism of the base ring + - ``morphism`` -- an automorphism of the base ring + + - ``derivation`` -- a derivation or a twisted derivation of the base ring - ``name`` -- string or list of strings representing the name of the variables of ring @@ -150,7 +394,7 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) def _element_constructor_(self, a=None, check=True, construct=False, **kwds): r""" Convert a base ring element ``a`` into a constant of this univariate - skew polynomial ring, possibly non-canonically. + Ore polynomial ring, possibly non-canonically. INPUT: @@ -163,7 +407,7 @@ def _element_constructor_(self, a=None, check=True, construct=False, **kwds): OUTPUT: - An zero-degree skew polynomial in ``self``, equal to ``a``. + An zero-degree Ore polynomial in ``self``, equal to ``a``. EXAMPLES:: @@ -221,13 +465,13 @@ def _coerce_map_from_base_ring(self): EXAMPLES:: sage: R. = ZZ[] - sage: S. = SkewPolynomialRing(R, R.hom([t + 1])) + sage: S. = OrePolynomialRing(R, R.hom([t + 1])) sage: S.coerce_map_from(R) - Skew Polynomial base injection morphism: + Ore Polynomial base injection morphism: From: Univariate Polynomial Ring in t over Integer Ring - To: Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + To: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 sage: x.parent() - Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 sage: t.parent() Univariate Polynomial Ring in t over Integer Ring sage: y = x + t # indirect doctest @@ -248,7 +492,7 @@ def _coerce_map_from_(self, P): - any ring that canonically coerces to the base ring of this ring - - skew polynomial rings in the same variable and automorphism over + - Ore polynomial rings in the same variable and automorphism over any base ring that canonically coerces to the base ring of this ring INPUT: @@ -259,7 +503,7 @@ def _coerce_map_from_(self, P): sage: R. = ZZ[] sage: sigma = R.hom([t+1]) - sage: S. = SkewPolynomialRing(R,sigma) + sage: S. = OrePolynomialRing(R,sigma) sage: S.has_coerce_map_from(S) True sage: S.has_coerce_map_from(R) @@ -272,16 +516,16 @@ def _coerce_map_from_(self, P): sage: S.coerce_map_from(ZZ) Composite map: From: Integer Ring - To: Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + To: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 Defn: Polynomial base injection morphism: From: Integer Ring To: Univariate Polynomial Ring in t over Integer Ring then - Skew Polynomial base injection morphism: + Ore Polynomial base injection morphism: From: Univariate Polynomial Ring in t over Integer Ring - To: Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + To: Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 sage: S.coerce_map_from(S) - Identity endomorphism of Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + Identity endomorphism of Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 """ base_ring = self.base_ring() try: @@ -300,20 +544,27 @@ def _repr_(self): r""" Return a string representation of ``self``. + The locution *Ore Polynomial Ring* is used when the twisting + derivation is zero. + Otherwise the locution *Ore Polynomial Ring* is used. + EXAMPLES:: - sage: R. = ZZ[] + sage: R. = QQ[] sage: sigma = R.hom([t+1]) - sage: S. = SkewPolynomialRing(R,sigma) + sage: S. = OrePolynomialRing(R, sigma) sage: S - Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + + sage: der = R.derivation() + sage: T. = OrePolynomialRing(R, der) + sage: T + Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt """ + s = "Ore Polynomial Ring in %s over %s twisted by " % (self.variable_name(), self.base_ring()) if self._derivation is None: - s = "Skew Polynomial Ring in %s over %s twisted by %s" % (self.variable_name(), - self.base_ring(), - self._morphism._repr_short()) + s += self._morphism._repr_short() else: - s = "Ore Polynomial Ring in %s over %s twisted by " % (self.variable_name(), self.base_ring()) if self._morphism is not None: s += "%s and " % self._morphism._repr_short() s += self._derivation._repr_() @@ -327,16 +578,20 @@ def _latex_(self): EXAMPLES:: - sage: R. = ZZ[] - sage: sigma = R.hom([t+1]) - sage: S. = SkewPolynomialRing(R,sigma) - sage: latex(S) - \Bold{Z}[t][x,\begin{array}{l} - \text{\texttt{Ring{ }endomorphism...}} - \end{array}] + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: latex(S) # indirect doctest + \Bold{F}_{5^{3}}\left[x ; a \mapsto a^{5} \right] + + sage: R. = QQ[] + sage: der = R.derivation() + sage: T. = R['d', der] + sage: latex(T) # indirect doctest + \Bold{Q}[t]\left[d ; \text{\texttt{d/dt}} \right] """ from sage.misc.latex import latex - s = "%s\\left[%s" % latex(self.base_ring(), self._latex_variable_names()[0]) + s = "%s\\left[%s" % (latex(self.base_ring()), self.latex_variable_names()[0]) sep = ";" if self._morphism is not None: s += sep + latex(self._morphism) @@ -347,8 +602,8 @@ def _latex_(self): def change_var(self, var): r""" - Return the skew polynomial ring in variable ``var`` with the same base - ring and twist map as ``self``. + Return the Ore polynomial ring in variable ``var`` with the same base + ring, twisting morphism and twisting derivation as ``self``. INPUT: @@ -362,10 +617,10 @@ def change_var(self, var): sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: R. = SkewPolynomialRing(k,Frob); R - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + sage: R. = OrePolynomialRing(k,Frob); R + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 sage: Ry = R.change_var('y'); Ry - Skew Polynomial Ring in y over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in y over Finite Field in t of size 5^3 twisted by t |--> t^5 sage: Ry is R.change_var('y') True """ @@ -398,7 +653,8 @@ def characteristic(self): @cached_method def twisting_morphism(self, n=1): r""" - Return the twisting endomorphism of the base ring iterated ``n`` times. + Return the twisting endomorphism defining this Ore polynomial ring iterated ``n`` times + or ``None`` if this Ore polynomial ring is not twisted by an endomorphism. INPUT: @@ -408,7 +664,7 @@ def twisting_morphism(self, n=1): sage: R. = QQ[] sage: sigma = R.hom([t+1]) - sage: S. = R['x',sigma] + sage: S. = R['x', sigma] sage: S.twisting_morphism() Ring endomorphism of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t + 1 @@ -419,7 +675,7 @@ def twisting_morphism(self, n=1): Defn: t |--> t + 10 If ``n`` in negative, Sage tries to compute the inverse of the - twist map:: + twisting morphism:: sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() @@ -427,13 +683,38 @@ def twisting_morphism(self, n=1): sage: T.twisting_morphism(-1) Frobenius endomorphism t |--> t^(5^2) on Finite Field in t of size 5^3 - Sometimes it fails, even if the twist map is actually invertible:: + Sometimes it fails, even if the twisting morphism is actually invertible:: sage: S.twisting_morphism(-1) Traceback (most recent call last): ... NotImplementedError: inversion of the twisting morphism Ring endomorphism of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t + 1 + + When the Ore polynomial ring is only twisted by a derivation, this + method returns nothing:: + + sage: der = R.derivation() + sage: A. = R['x', der] + sage: A + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by d/dt + sage: A.twisting_morphism() + + Here is an example where the twisting morphism is automatically + infered from the derivation:: + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: der = k.derivation(1, twist=Frob) + sage: der + [a |--> a^5] - id + sage: S. = k['x', der] + sage: S.twisting_morphism() + Frobenius endomorphism a |--> a^5 on Finite Field in a of size 5^3 + + .. SEEALSO:: + + :meth:`twisting_derivation` """ if self._morphism is not None: try: @@ -444,18 +725,63 @@ def twisting_morphism(self, n=1): else: raise ValueError("Unexpected error in iterating the twisting morphism: %s", e) - def twist_map(self, n): - # Deprecation + def twist_map(self, n=1): + r""" + Return the twisting endomorphism defining this Ore polynomial ring iterated ``n`` times + or ``None`` if this Ore polynomial ring is not twisted by an endomorphism. + + This method is deprecated. You should use :meth:`twisting_morphism` instead. + + INPUT: + + - ``n`` - an integer (default: 1) + + EXAMPLES:: + + sage: R. = QQ[] + sage: sigma = R.hom([t+1]) + sage: S. = R['x', sigma] + sage: S.twist_map() + ... + DeprecationWarning: The method twist_map is deprecated; use twisting_morphism (same semantic) instead + See https://trac.sagemath.org/29629 for details. + Ring endomorphism of Univariate Polynomial Ring in t over Rational Field + Defn: t |--> t + 1 + """ + from sage.misc.superseded import deprecation + deprecation(29629, "The method twist_map is deprecated; use twisting_morphism (same semantic) instead") return self.twisting_morphism(n) def twisting_derivation(self): + r""" + Return the twisting derivation defining this Ore polynomial ring + or ``None`` if this Ore polynomial ring is not twisted by a derivation. + + EXAMPLES:: + + sage: R. = QQ[] + sage: der = R.derivation(); der + d/dt + sage: A. = R['d', der] + sage: A.twisting_derivation() + d/dt + + sage: k. = GF(5^3) + sage: Frob = k.frobenius_endomorphism() + sage: S. = k['x', Frob] + sage: S.twisting_derivation() + + .. SEEALSO:: + + :meth:`twisting_morphism` + """ return self._derivation @cached_method def gen(self, n=0): r""" - Return the indeterminate generator of this skew polynomial ring. + Return the indeterminate generator of this Ore polynomial ring. INPUT: @@ -467,7 +793,7 @@ def gen(self, n=0): sage: R. = QQ[] sage: sigma = R.hom([t+1]) sage: S. = R['x',sigma]; S - Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 + Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Rational Field twisted by t |--> t + 1 sage: y = S.gen(); y x sage: y == x @@ -490,7 +816,8 @@ def gen(self, n=0): def gens_dict(self): r""" - Return a {name: variable} dictionary of the generators of ``self``. + Return a {name: variable} dictionary of the generators of + this Ore polynomial ring. EXAMPLES:: @@ -504,7 +831,7 @@ def gens_dict(self): def is_finite(self): r""" - Return ``False`` since skew polynomial rings are not finite + Return ``False`` since Ore polynomial rings are not finite (unless the base ring is `0`.) EXAMPLES:: @@ -522,14 +849,14 @@ def is_finite(self): def is_exact(self): r""" - Return ``True`` if elements of this skew polynomial ring are exact. + 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:: sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: S. = k['x',Frob] + sage: S. = k['x', Frob] sage: S.is_exact() True sage: S.base_ring().is_exact() @@ -537,7 +864,7 @@ def is_exact(self): sage: R. = k[[]] sage: sigma = R.hom([u+u^2]) - sage: T. = R['y',sigma] + sage: T. = R['y', sigma] sage: T.is_exact() False sage: T.base_ring().is_exact() @@ -547,12 +874,12 @@ def is_exact(self): def is_sparse(self): r""" - Return ``True`` if the elements of this polynomial ring are sparsely + Return ``True`` if the elements of this Ore polynomial ring are sparsely represented. .. WARNING:: - Since sparse skew polynomials are not yet implemented, this + Since sparse Ore polynomials are not yet implemented, this function always returns ``False``. EXAMPLES:: @@ -567,8 +894,8 @@ def is_sparse(self): def ngens(self): r""" - Return the number of generators of this skew polynomial ring, - which is 1. + Return the number of generators of this Ore polynomial ring, + which is `1`. EXAMPLES:: @@ -582,7 +909,7 @@ def ngens(self): def random_element(self, degree=2, monic=False, *args, **kwds): r""" - Return a random skew polynomial in ``self``. + Return a random Ore polynomial in this ring. INPUT: @@ -590,14 +917,14 @@ def random_element(self, degree=2, monic=False, *args, **kwds): or a tuple of integers with minimum and maximum degrees - ``monic`` -- (default: ``False``) if ``True``, return a monic - skew polynomial + Ore polynomial - ``*args, **kwds`` -- passed on to the ``random_element`` method for the base ring OUTPUT: - Skew polynomial such that the coefficients of `x^i`, for `i` up + Ore polynomial such that the coefficients of `x^i`, for `i` up to ``degree``, are random elements from the base ring, randomized subject to the arguments ``*args`` and ``**kwds``. @@ -616,7 +943,7 @@ def random_element(self, degree=2, monic=False, *args, **kwds): sage: p = S.random_element(degree=5) # random (t^2 + 3*t)*x^4 + (4*t + 4)*x^3 + (4*t^2 + 4*t)*x^2 + (2*t^2 + 1)*x + 3 - When ``monic`` is ``False``, the returned skew polynomial may have + When ``monic`` is ``False``, the returned Ore polynomial may have a degree less than ``degree`` (it happens when the random leading coefficient is zero). However, if ``monic`` is ``True``, this can't happen:: @@ -635,7 +962,7 @@ def random_element(self, degree=2, monic=False, *args, **kwds): (3*t^2 + 1)*x^4 + (4*t + 2)*x^3 + (4*t + 1)*x^2 + (t^2 + 3*t + 3)*x + 3*t^2 + 2*t + 2 - If the first tuple element is greater than the second, a a + If the first tuple element is greater than the second, a ``ValueError`` is raised:: sage: S.random_element(degree=(5,4)) @@ -657,11 +984,11 @@ def random_element(self, degree=2, monic=False, *args, **kwds): def random_irreducible(self, degree=2, monic=True, *args, **kwds): r""" - Return a random irreducible skew polynomial. + Return a random irreducible Ore polynomial. .. WARNING:: - Elements of this skew polynomial ring need to have a method + Elements of this Ore polynomial ring need to have a method is_irreducible(). Currently, this method is implemented only when the base ring is a finite field. @@ -670,16 +997,12 @@ def random_irreducible(self, degree=2, monic=True, *args, **kwds): - ``degree`` - Integer with degree (default: 2) or a tuple of integers with minimum and maximum degrees - - ``monic`` - if True, returns a monic skew polynomial - (default: True) + - ``monic`` - if ``True``, returns a monic Ore polynomial + (default: ``True``) - - ``*args, **kwds`` - Passed on to the ``random_element`` method for + - ``*args, **kwds`` - passed on to the ``random_element`` method for the base ring - OUTPUT: - - - A random skew polynomial - EXAMPLES:: sage: k. = GF(5^3) @@ -707,19 +1030,29 @@ def random_irreducible(self, degree=2, monic=True, *args, **kwds): def is_commutative(self): r""" - Return ``True`` if this skew polynomial ring is commutative, i.e. if the - twist map is the identity. + Return ``True`` if this Ore polynomial ring is commutative, i.e. if the + twisting morphism is the identity and the twisting derivation vanishes. EXAMPLES:: - sage: k. = GF(5^3) + sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() - sage: S. = k['x',Frob] + sage: S. = k['x', Frob] sage: S.is_commutative() False - sage: T. = k['y',Frob^3] + sage: T. = k['y', Frob^3] sage: T.is_commutative() True + + sage: R. = GF(5)[] + sage: der = R.derivation() + sage: A. = R['d', der] + sage: A.is_commutative() + False + + sage: B. = R['b', 5*der] + sage: B.is_commutative() + True """ - return self.twisting_morphism().is_identity() + return self._morphism is None and self._derivation is None diff --git a/src/sage/rings/polynomial/skew_polynomial_element.pyx b/src/sage/rings/polynomial/skew_polynomial_element.pyx index cee93bf4a1f..31454f5f916 100644 --- a/src/sage/rings/polynomial/skew_polynomial_element.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_element.pyx @@ -2,18 +2,9 @@ r""" Univariate Skew Polynomials This module provides the -:class:`~sage.rings.polynomial.skew_polynomial_element.SkewPolynomial`, -which constructs a single univariate skew polynomial over commutative -base rings and an automorphism over the base ring. Skew polynomials are -non-commutative and so principal methods such as gcd, lcm, monic, -multiplication, and division are given in left and right forms. - -The generic implementation of dense skew polynomials is -:class:`~sage.rings.polynomial.skew_polynomial_element.SkewPolynomial_generic_dense`. -The classes -:class:`~sage.rings.polynomial.skew_polynomial_element.ConstantSkewPolynomialSection` -and :class:`~sage.rings.polynomial.skew_polynomial_element.SkewPolynomialBaseringInjection` -handle conversion from a skew polynomial ring to its base ring and vice versa respectively. +:class:`~sage.rings.polynomial.skew_polynomial_element.SkewPolynomial`. +In the class hierarchy in Sage, the locution *Skew Polynomial* is used +for a Ore polynomial without twisting derivation. .. WARNING:: @@ -29,9 +20,8 @@ handle conversion from a skew polynomial ring to its base ring and vice versa re sage: S. = R['x',sigma] sage: a = 2*(t + x) + 1 sage: a(t^2) - doctest:...: FutureWarning: This class/method/function is marked as - experimental. It, its functionality or its interface might change - without a formal deprecation. + doctest:...: FutureWarning: This class/method/function is marked as experimental. + It, its functionality or its interface might change without a formal deprecation. See http://trac.sagemath.org/13215 for details. 2*t^3 + 3*t^2 + 4*t + 2 sage: a(t) @@ -85,7 +75,7 @@ from sage.rings.polynomial.ore_polynomial_element cimport OrePolynomial_generic_ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): r""" Generic implementation of dense skew polynomial supporting any valid base - ring and twist map. + ring and twisting morphism. """ cpdef left_power_mod(self, exp, modulus): r""" @@ -272,7 +262,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): Given a skew polynomial `p(x) = \sum_{i=0}^d a_i * x^i`, we define the evaluation `p(r)` to be `\sum_{i=0}^d a_i * \sigma^i(r)`, where - `\sigma` is the twist map of the skew polynomial ring. + `\sigma` is the twisting morphism of the skew polynomial ring. INPUT: @@ -355,7 +345,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): sage: a.operator_eval(t) 2*t^2 + 2*t + 3 - Evaluation points outside the base ring is usually not possible due to the twist map:: + Evaluation points outside the base ring is usually not possible due to the twisting morphism:: sage: R. = QQ[] sage: sigma = R.hom([t+1]) @@ -381,7 +371,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): variable of ``self``. The conjugate is obtained from ``self`` by applying the `n`-th iterate - of the twist map to each of its coefficients. + of the twisting morphism to each of its coefficients. INPUT: @@ -399,7 +389,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): True In principle, negative values for `n` are allowed, but Sage needs to be - able to invert the twist map:: + able to invert the twisting morphism:: sage: b = a.conjugate(-1) Traceback (most recent call last): @@ -459,7 +449,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): cpdef ModuleElement _lmul_(self, Element right): r""" - Multiply ``self`` on the right by scalar. + Return the product ``self * right``. INPUT: @@ -488,7 +478,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): cpdef ModuleElement _rmul_(self, Element left): r""" - Multiply ``self`` on the left by scalar. + Return the product ``left * self``. INPUT: @@ -515,11 +505,11 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): cpdef _mul_(self, right): r""" - Multiply ``self`` on the right by a skew polynomial. + Return the product ``self * right``. INPUT: - - ``right`` -- a skew polynomial in the same ring as ``self`` + - ``right`` -- a Ore polynomial in the same ring as ``self`` EXAMPLES:: @@ -649,7 +639,7 @@ cdef class SkewPolynomial_generic_dense(OrePolynomial_generic_dense): for j from 0 <= j < db: a[i+j] -= b[j] * parent.twisting_morphism(j)(c) except Exception: - raise NotImplementedError("inversion of the twist map %s" % parent.twisting_morphism()) + raise NotImplementedError("inversion of the twisting morphism %s" % parent.twisting_morphism()) q.append(c) q.reverse() return (self._new_c(q, parent), self._new_c(a[:db], parent, 1)) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx index b854ceeb2c9..ac6288866f0 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_field.pyx @@ -159,7 +159,7 @@ cdef class SkewPolynomial_finite_field_dense(SkewPolynomial_finite_order_dense): [] If `a = N`, the type is just `[r]` where `r` is the order - of the twist map ``Frob``:: + of the twisting morphism ``Frob``:: sage: N = x3^2 + x3 + 1 sage: S(N).type(N) diff --git a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx index 1e70849dfbd..afe08a36caa 100644 --- a/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx +++ b/src/sage/rings/polynomial/skew_polynomial_finite_order.pyx @@ -50,7 +50,7 @@ cdef class SkewPolynomial_finite_order_dense(SkewPolynomial_generic_dense): sage: R. = GF(5^3) sage: Frob = R.frobenius_endomorphism() sage: S. = R['x', Frob]; S - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 We create a skew polynomial from a list:: diff --git a/src/sage/rings/polynomial/skew_polynomial_ring.py b/src/sage/rings/polynomial/skew_polynomial_ring.py index 3faff223f62..a78cf2f3502 100644 --- a/src/sage/rings/polynomial/skew_polynomial_ring.py +++ b/src/sage/rings/polynomial/skew_polynomial_ring.py @@ -1,18 +1,23 @@ r""" Skew Univariate Polynomial Rings -This module provides the :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing` -which constructs a general dense skew univariate polynomials over commutative base rings with -automorphisms over the base rings. This is the set of formal polynomials where the coefficients -are written on the left of the variable of the skew polynomial ring. The modified multiplication -operation over elements of the base ring is extended to all elements of the skew poynomial ring -by associativity and distributivity. - -This module also provides :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order` -which is a specialized class for skew polynomial rings over fields equipped with an automorphism of -finite order. It inherits from -:class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing` but contains more -methods and provides better algorithms. +This module provides the :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing`. +In the class hierarchy in Sage, the locution *Skew Polynomial* is used for a Ore polynomial +without twisting derivation. + +This module also provides: + +- the class :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order` + which is a specialized class for skew polynomial rings over fields equipped with an automorphism of + finite order. It inherits from :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing` + but contains more methods and provides better algorithms. + +- the class :class:`~sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_field` + which is a specialized class for skew polynomial rings over finite fields. + +.. SEEALSO:: + + :class:`~sage.rings.polynomial.ore_polynomial_ring.OrePolynomialRing` AUTHOR: @@ -79,7 +84,7 @@ def _base_ring_to_fraction_field(S): sage: sigma = R.hom([t+1]) sage: S. = R['x', sigma] sage: _base_ring_to_fraction_field(S) - Skew Polynomial Ring in x over Fraction Field of Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 + Ore Polynomial Ring in x over Fraction Field of Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1 """ R = S.base_ring() if isinstance(R, Field): @@ -92,7 +97,7 @@ def _base_ring_to_fraction_field(S): sigmaQ = Q.hom([Q(sigmaS(g)) for g in gens]) return Q[S.variable_name(), sigmaQ] # except Exception, e: - # raise ValueError("unable to lift the twist map to a twist map over %s (error was: %s)" % (Q, e)) + # raise ValueError("unable to lift the twisting morphism to a twisting morphism over %s (error was: %s)" % (Q, e)) def _minimal_vanishing_polynomial(R, eval_pts): @@ -180,7 +185,7 @@ def _lagrange_polynomial(R, eval_pts, values): True The following restrictions are impossible to satisfy because the evaluation - points are linearly dependent over the fixed field of the twist map, and the + points are linearly dependent over the fixed field of the twisting morphism, and the corresponding values do not match:: sage: eval_pts = [ t, 2*t ] @@ -188,14 +193,14 @@ def _lagrange_polynomial(R, eval_pts, values): sage: _lagrange_polynomial(S, eval_pts, values) Traceback (most recent call last): ... - ValueError: the given evaluation points are linearly dependent over the fixed field of the twist map, + ValueError: the given evaluation points are linearly dependent over the fixed field of the twisting morphism, so a Lagrange polynomial could not be determined (and might not exist). """ l = len(eval_pts) if l == 1: if eval_pts[0].is_zero(): # This is due to linear dependence among the eval_pts. - raise ValueError("the given evaluation points are linearly dependent over the fixed field of the twist map, so a Lagrange polynomial could not be determined (and might not exist).") + raise ValueError("the given evaluation points are linearly dependent over the fixed field of the twisting morphism, so a Lagrange polynomial could not be determined (and might not exist).") return (values[0] / eval_pts[0]) * R.one() else: t = l // 2 @@ -259,7 +264,7 @@ def minimal_vanishing_polynomial(self, eval_pts): are linearly independent over the fixed field of ``self.twisting_morphism()``. - ``eval_pts`` -- list of evaluation points which are linearly - independent over the fixed field of the twist map of the associated + independent over the fixed field of the twisting morphism of the associated skew polynomial ring OUTPUT: @@ -281,7 +286,7 @@ def minimal_vanishing_polynomial(self, eval_pts): [0, 0, 0] If the evaluation points are linearly dependent over the fixed field of - the twist map, then the returned polynomial has lower degree than the + the twisting morphism, then the returned polynomial has lower degree than the number of evaluation points:: sage: S.minimal_vanishing_polynomial([t]) @@ -341,7 +346,7 @@ def lagrange_polynomial(self, points): sage: T.lagrange_polynomial([ (t, 1), (2*t, 3) ]) Traceback (most recent call last): ... - ValueError: the given evaluation points are linearly dependent over the fixed field of the twist map, + ValueError: the given evaluation points are linearly dependent over the fixed field of the twisting morphism, so a Lagrange polynomial could not be determined (and might not exist). """ l = len(points) @@ -456,7 +461,7 @@ def __init__(self, domain, codomain, embed, order): sage: S. = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() sage: S.convert_map_from(Z) # indirect doctest - Embedding of the center of Skew Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring + Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring """ RingHomomorphism.__init__(self, Hom(domain, codomain)) self._embed = embed @@ -475,9 +480,9 @@ def _repr_(self): sage: Z = S.center() sage: iota = S.convert_map_from(Z) sage: iota - Embedding of the center of Skew Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring + Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring sage: iota._repr_() - 'Embedding of the center of Skew Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring' + 'Embedding of the center of Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5 into this ring' """ return "Embedding of the center of %s into this ring" % self._codomain @@ -559,7 +564,7 @@ def __init__(self, base_ring, morphism, derivation, name, sparse, category=None) sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x', Frob]; S - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 sage: S.category() Category of algebras over Finite Field in t of size 5^3 @@ -621,7 +626,7 @@ def center(self, name=None, names=None, default=False): sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S. = k['x',Frob]; S - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 sage: Z = S.center(); Z Univariate Polynomial Ring in z over Finite Field of size 5 @@ -648,7 +653,7 @@ def center(self, name=None, names=None, default=False): sage: P = y + x; P x^3 + x sage: P.parent() - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 sage: P.parent() is S True @@ -777,7 +782,7 @@ def __init__(self, base_ring, morphism, derivation, names, sparse, category=None sage: k. = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: T. = k['x', Frob]; T - Skew Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 + Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 """ if self.Element is None: import sage.rings.polynomial.skew_polynomial_finite_field