Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
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.
.. WARNING::
The current semantics of :meth:`~sage.rings.polynomial.skew_polynomial_element.SkewPolynomial.__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.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = 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
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
"""
############################################################################# # Copyright (C) 2012 Xavier Caruso <xavier.caruso@normalesup.org> # # 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 # the Free Software Foundation, either version 2 of the License, or # (at your option) any later version. # http://www.gnu.org/licenses/ #****************************************************************************
from __future__ import print_function, absolute_import, division
from sage.structure.element cimport Element, RingElement, AlgebraElement, ModuleElement from sage.structure.parent cimport Parent from sage.structure.parent_gens cimport ParentWithGens from sage.rings.integer cimport Integer from cpython.object cimport PyObject_RichCompare from sage.categories.map cimport Map from sage.rings.morphism cimport Morphism, RingHomomorphism from sage.rings.polynomial.polynomial_element cimport _dict_to_list
cdef class SkewPolynomial(AlgebraElement): r""" Abstract base class for skew 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`.
Then, a skew polynomial is given by the equation:
.. MATH::
F(X) = a_{n} X^{n} + \cdots + a_0,
where the coefficients `a_i \in R` and `X` is a formal variable.
Addition between two skew 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.
Let `a` and `b` be two skew 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
- `a = q b + r` (resp. `a = b q + r`)
- the degree of `r` is less than the degree of `b`
`q` (resp. `r`) is called the *quotient* (resp. the remainder) of this euclidean division.
.. RUBRIC:: Properties
Keeping the previous notation, if the leading coefficient of `b` is a unit (e.g. if `b` is monic) then the quotient and the remainder 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.
EXAMPLES:
We illustrate some functionalities implemented in this class.
We create the skew polynomial ring::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma]; S Skew Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring twisted by t |--> t + 1
and some elements in it::
sage: a = t + x + 1; a x + t + 1 sage: b = S([t^2,t+1,1]); b x^2 + (t + 1)*x + t^2 sage: c = S.random_element(degree=3,monic=True); c x^3 + (-95*t^2 + t + 2)*x^2 + (-t^2 + t)*x + 2*t - 8
Ring operations are supported::
sage: a + b x^2 + (t + 2)*x + t^2 + t + 1 sage: a - b -x^2 - t*x - t^2 + t + 1
sage: a * b x^3 + (2*t + 3)*x^2 + (2*t^2 + 4*t + 2)*x + t^3 + t^2 sage: b * a x^3 + (2*t + 4)*x^2 + (2*t^2 + 3*t + 2)*x + t^3 + t^2 sage: a * b == b * a False
sage: b^2 x^4 + (2*t + 4)*x^3 + (3*t^2 + 7*t + 6)*x^2 + (2*t^3 + 4*t^2 + 3*t + 1)*x + t^4 sage: b^2 == b*b True
Sage also implements arithmetic over skew polynomial rings. You will find below a short panorama::
sage: q,r = c.right_quo_rem(b) sage: q x - 95*t^2 sage: r (95*t^3 + 93*t^2 - t - 1)*x + 95*t^4 + 2*t - 8 sage: c == q*b + r True
The operators ``//`` and ``%`` give respectively the quotient and the remainder of the *right* euclidean division::
sage: q == c // b True sage: r == c % b True
Left euclidean division won't work over our current `S` because Sage can't invert the twist map::
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 Defn: t |--> t + 1
Here we can see the effect of the operator evaluation compared to the usual polynomial evaluation::
sage: a = x^2 sage: a(t) t + 2
Here is a working example over a finite field::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^4 + (4*t + 1)*x^3 + (t^2 + 3*t + 3)*x^2 + (3*t^2 + 2*t + 2)*x + (3*t^2 + 3*t + 1) sage: b = (2*t^2 + 3)*x^2 + (3*t^2 + 1)*x + 4*t + 2 sage: q,r = a.left_quo_rem(b) sage: q (4*t^2 + t + 1)*x^2 + (2*t^2 + 2*t + 2)*x + 2*t^2 + 4*t + 3 sage: r (t + 2)*x + 3*t^2 + 2*t + 4 sage: a == b*q + r True
Once we have euclidean divisions, we have for free gcd and lcm (at least if the base ring is a field)::
sage: a = (x + t) * (x + t^2)^2 sage: b = (x + t) * (t*x + t + 1) * (x + t^2) sage: a.right_gcd(b) x + t^2 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 polynomials `u, v`. Such a `c` always exist if the base ring is a field::
sage: c = a.left_lcm(b); c x^5 + (4*t^2 + t + 3)*x^4 + (3*t^2 + 4*t)*x^3 + 2*t^2*x^2 + (2*t^2 + t)*x + 4*t^2 + 4 sage: c.is_right_divisible_by(a) True sage: c.is_right_divisible_by(b) True
The right lcm is defined similarly as the least degree polynomial `c = au = bv` for some `u,v`::
sage: d = a.right_lcm(b); d x^5 + (t^2 + 1)*x^4 + (3*t^2 + 3*t + 3)*x^3 + (3*t^2 + t + 2)*x^2 + (4*t^2 + 3*t)*x + 4*t + 4 sage: d.is_left_divisible_by(a) True sage: d.is_left_divisible_by(b) True
.. SEEALSO::
- :mod:`sage.rings.polynomial.skew_polynomial_ring` - :mod:`sage.rings.polynomial.skew_polynomial_ring_constructor` """ def __init__(self, parent, construct=False): r""" Initialize ``self``.
INPUT:
- ``parent`` -- parent of ``self``
- ``construct`` -- boolean (default: ``False``)
TESTS::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: P = x + t sage: TestSuite(P).run() sage: Q = S([1, t, t+2]) sage: TestSuite(Q).run() """
cdef long _hash_c(self): raise NotImplementedError
def __hash__(self): r""" Return hash of ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: hash(a) == hash(a) True """
cdef void _inplace_rmul(self, SkewPolynomial_generic_dense right): raise NotImplementedError cdef void _inplace_pow(self, Py_ssize_t n): raise NotImplementedError
cpdef int degree(self): r""" Return the degree of ``self``.
By convention, the zero skew polynomial has degree `-1`.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2 + t*x^3 + t^2*x + 1 sage: a.degree() 3 sage: S.zero().degree() -1 sage: S(5).degree() 0 """
cdef SkewPolynomial _new_c(self, list coeffs, Parent P, char check=0): r""" Fast creation of a new skew polynomial
.. NOTE::
Override this function in classes which inherit from SkewPolynomial. """ l = P(coeffs) return l
cpdef SkewPolynomial _new_constant_poly(self, RingElement a, Parent P, char check=0): r""" Fast creation of a new constant skew polynomial
EXAMPLES::
sage: from sage.rings.polynomial.skew_polynomial_element import SkewPolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: SkewPolynomialBaseringInjection(k, k['x', Frob]) #indirect doctest Skew 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 """ if a: n = self._new_c([a],P,check) else: n = self._new_c([],P) return n
def __call__(self, eval_pt): r""" Evaluate ``self`` at ``eval_pt`` using operator evaluation.
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.
INPUT:
- ``eval_pt`` -- element of the base ring of ``self``
OUTPUT:
The operator evaluation of ``self`` at ``eval_pt``.
.. TODO::
Currently, only "operator evaluation" of skew polynomials is implemented (see :meth:`.operator_eval`). There are two other notions of evaluation of a skew polynomial `p(x)` at some element `a` of the base ring. First, the value of the polynomial can be defined as the remainder of the right division of `p(x)` by `x-a`. Second, the value can be given by the formula, `p(a) = \sum_{i=0}^{m-1} B_{i} * p(\beta_{i})` where `m` is the degree of the base ring (`F_{q^m}`) of the skew polynomial ring, `B_{i}` is the `i`-th element in the vector representation of `a` in `F_{q}` and`\beta_{i}` is the `i`-th element of the corresponding basis of `F_{q^m}` over `F_{q}`.
The current calling convention might change in the future to accommodate these. Therefore, the current method has been marked as experimental.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x + 1 sage: a(t^2) t^3 + 3*t^2 + t sage: b = x^2 + t*x^3 + t^2*x + 1 sage: b(2*t + 3) 2*t^3 + 7*t^2 + 13*t + 10 """
r""" Helper function for the :meth:`__call__` method to accommodate the ``@experimental`` decorator.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: T.<x> = k['x',Frob] sage: a = 3*t^2*x^2 + (t + 1)*x + 2 sage: a(t) #indirect test 2*t^2 + 2*t + 3 """
cpdef operator_eval(self, eval_pt): r""" Evaluate ``self`` at ``eval_pt`` by the operator evaluation method.
INPUT:
- ``eval_pt`` -- element of the base ring of ``self``
OUTPUT:
The value of the polynomial at the point specified by the argument.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: T.<x> = k['x',Frob] sage: a = 3*t^2*x^2 + (t + 1)*x + 2 sage: a(t) #indirect test 2*t^2 + 2*t + 3 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::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x + 1 sage: a.operator_eval(1/t) Traceback (most recent call last): ... TypeError: 1/t fails to convert into the map's domain Univariate Polynomial Ring in t over Rational Field, but a `pushforward` method is not properly implemented """
def __setitem__(self, n, value): r""" Set the ``n``-th coefficient of ``self``.
This always raises an ``IndexError``, since polynomials are immutable in Sage.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: a[1] = t + 1 Traceback (most recent call last): ... IndexError: skew polynomials are immutable """
def square(self): r""" Return the square of ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = 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 """
def conjugate(self, n): r""" Return ``self`` conjugated by `x^n`, where `x` is the variable of ``self``.
The conjugate is obtained from ``self`` by applying the `n`-th iterate of the twist map to each of its coefficients.
INPUT:
- `n` -- an integer, the power of conjugation
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x^3 + (t^2 + 1)*x^2 + 2*t sage: b = a.conjugate(2); b (t + 2)*x^3 + (t^2 + 4*t + 5)*x^2 + 2*t + 4 sage: x^2*a == b*x^2 True
In principle, negative values for `n` are allowed, but Sage needs to be able to invert the twist map::
sage: b = a.conjugate(-1) Traceback (most recent call last): ... NotImplementedError: inversion of the twist map Ring endomorphism of Univariate Polynomial Ring in t over Rational Field Defn: t |--> t + 1
Here is a working example::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: T.<y> = k['y',Frob] sage: u = T.random_element(); u (2*t^2 + 3)*y^2 + (4*t^2 + t + 4)*y + 2*t^2 + 2 sage: v = u.conjugate(-1); v (3*t^2 + t)*y^2 + (4*t^2 + 2*t + 4)*y + 3*t^2 + t + 4 sage: u*y == y*v True """
def constant_coefficient(self): r""" Return the constant coefficient (i.e. the coefficient of term of degree `0`) of ``self``.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + t^2 + 2 sage: a.constant_coefficient() t^2 + 2 """ else:
def leading_coefficient(self): r""" Return the coefficient of the highest-degree monomial of ``self``.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (t+1)*x^5 + t^2*x^3 + x sage: a.leading_coefficient() t + 1 """ raise ValueError("the skew polynomial must not be 0")
def is_unit(self): r""" Return ``True`` if this skew polynomial is a unit.
When the base ring `R` is an integral domain, then a skew polynomial `f` is a unit if and only if degree of `f` is `0` and `f` is then a unit in `R`.
.. NOTE::
The case when `R` is not an integral domain is not yet implemented.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + (t+1)*x^5 + t^2*x^3 - x^5 sage: a.is_unit() False """ # TODO: Sage does not yet have support for finding order of # automorphisms. Once that is available, general case can # be implemented. Reference: http://bit.ly/29Vidu7 return True else: else: raise NotImplementedError("is_unit is not implemented for skew 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. 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.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: x.is_nilpotent() Traceback (most recent call last): ... NotImplementedError """
def is_monic(self): r""" Return ``True`` if this skew polynomial is monic.
The zero polynomial is by definition not monic.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + t sage: a.is_monic() True sage: a = 0*x sage: a.is_monic() False sage: a = t*x^3 + x^4 + (t+1)*x^2 sage: a.is_monic() True sage: a = (t^2 + 2*t)*x^2 + x^3 + t^10*x^5 sage: a.is_monic() False """
def left_monic(self): r""" Return the unique monic skew polynomial `m` which divides ``self`` 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.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 sage: b = a.left_monic(); b x^3 + (4*t^2 + 3*t)*x^2 + (4*t + 2)*x + 2*t^2 + 4*t + 3
Check list::
sage: b.degree() == a.degree() True sage: b.is_left_divisible_by(a) True sage: twist = S.twist_map(-a.degree()) sage: a == b * twist(a.leading_coefficient()) True
Note that `b` does not divide `a` on the right::
sage: a.is_right_divisible_by(b) False
This function does not work if the leading coefficient is not a unit::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x sage: a.left_monic() Traceback (most recent call last): ... NotImplementedError: the leading coefficient is not a unit """
def right_monic(self): r""" Return the unique monic skew polynomial `m` which divides ``self`` 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.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 sage: b = a.right_monic(); b x^3 + (2*t^2 + 3*t + 4)*x^2 + (3*t^2 + 4*t + 1)*x + 2*t^2 + 4*t + 3
Check list::
sage: b.degree() == a.degree() True sage: b.is_right_divisible_by(a) True sage: a == a.leading_coefficient() * b True
Note that `b` does not divide `a` on the right::
sage: a.is_left_divisible_by(b) False
This function does not work if the leading coefficient is not a unit::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x sage: a.right_monic() Traceback (most recent call last): ... NotImplementedError: the leading coefficient is not a unit """
cpdef _mod_(self, other): r""" Return the remainder in the *right* euclidean division of ``self`` by ``other```.
TESTS::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: b = x^2 + 2*t*x + 2 sage: a = (x+t)*b + t*x + 1 sage: a % b t*x + 1
sage: (a*t).right_quo_rem(b*t) Traceback (most recent call last): ... NotImplementedError: the leading coefficient of the divisor is not invertible """
cpdef _floordiv_(self, right): r""" Return the quotient of the *right* euclidean division of ``self`` by ``right``.
The algorithm fails if the leading coefficient of the divisor (``right``) is not invertible.
TESTS::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: b = x^2 + t sage: a = (x^2 + t*x + 1)*b + t^3*x sage: a // b x^2 + t*x + 1
sage: (t*a) // (t*b) Traceback (most recent call last): ... NotImplementedError: the leading coefficient of the divisor is not invertible
"""
cpdef _div_(self, right): r""" Not Implemented.
To implement this, localization of Ore rings is needed, see :trac:`13215`.
Use the operator `//` even for exact division.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^5 + (t + 2)*x^2 + t^2 sage: b = x^3 + 4*t sage: c = a*b
sage: c / b Traceback (most recent call last): ... NotImplementedError: localization of Ore rings not yet implemented
sage: c // b == a True """ # Should this actually return something in the fraction field like # we do elsewhere in Sage? - TCS
def is_left_divisible_by(self, other): r""" Check if ``self`` is divisible by ``other`` on the left.
INPUT:
- ``other`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Return ``True`` or ``False``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^2 + t*x + t^2 + 3 sage: b = x^3 + (t + 1)*x^2 + 1 sage: c = a*b sage: c.is_left_divisible_by(a) True sage: c.is_left_divisible_by(b) False
Divisibility by `0` does not make sense::
sage: c.is_left_divisible_by(S(0)) Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid """
def is_right_divisible_by(self, other): r""" Check if ``self`` is divisible by ``other`` on the right.
INPUT:
- ``other`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Return ``True`` or ``False``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^2 + t*x + t^2 + 3 sage: b = x^3 + (t + 1)*x^2 + 1 sage: c = a*b sage: c.is_right_divisible_by(a) False sage: c.is_right_divisible_by(b) True
Divisibility by `0` does not make sense::
sage: c.is_right_divisible_by(S(0)) Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid
This function does not work if the leading coefficient of the divisor is not a unit::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2 + 2*x + t sage: b = (t+1)*x + t^2 sage: c = a*b sage: c.is_right_divisible_by(b) Traceback (most recent call last): ... NotImplementedError: the leading coefficient of the divisor is not invertible """
def left_divides(self, other): r""" Check if ``self`` divides ``other`` on the left.
INPUT:
- ``other`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Return ``True`` or ``False``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^2 + t*x + t^2 + 3 sage: b = x^3 + (t + 1)*x^2 + 1 sage: c = a*b sage: a.left_divides(c) True sage: b.left_divides(c) False
Divisibility by `0` does not make sense::
sage: S(0).left_divides(c) Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid """
def right_divides(self, other): r""" Check if ``self`` divides ``other`` on the right.
INPUT:
- ``other`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Return ``True`` or ``False``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x^2 + t*x + t^2 + 3 sage: b = x^3 + (t + 1)*x^2 + 1 sage: c = a*b sage: a.right_divides(c) False sage: b.right_divides(c) True
Divisibility by `0` does not make sense::
sage: S(0).right_divides(c) Traceback (most recent call last): ... ZeroDivisionError: division by zero is not valid
This function does not work if the leading coefficient of the divisor is not a unit::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2 + 2*x + t sage: b = (t+1)*x + t^2 sage: c = a*b sage: b.right_divides(c) Traceback (most recent call last): ... NotImplementedError: the leading coefficient of the divisor is not invertible """
r""" 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 `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``
- ``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 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:
.. MATH::
g = a * u + b * v,
where `s` is ``self`` and `b` is ``other``.
.. NOTE::
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.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) sage: g,u,v = a.left_xgcd(b); g x + t sage: a*u + b*v == g True
Specifying ``monic=False``, we *can* get a nonmonic gcd::
sage: g,u,v = a.left_xgcd(b, monic=False); g 2*t*x + 4*t + 2 sage: a*u + b*v == g True
The base ring must be a field::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) sage: a.left_xgcd(b) Traceback (most recent call last): ... TypeError: the base ring must be a field
And the twist map must be bijective::
sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) sage: S.<x> = FR['x',f] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) 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 Defn: t |--> t^2 """ V = self._parent.zero() else:
r""" 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 `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``
- ``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 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:
.. MATH::
g = u * a + v * b
where `a` is ``self`` and `b` is ``other``.
.. NOTE::
Works only if the base ring is a field (otherwise right gcd do not exist in general).
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (x^2 + t*x + 1) * (x + t) sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) sage: g,u,v = a.right_xgcd(b); g x + t sage: u*a + v*b == g True
Specifying ``monic=False``, we *can* get a nonmonic gcd::
sage: g,u,v = a.right_xgcd(b,monic=False); g (4*t^2 + 4*t + 1)*x + 4*t^2 + 4*t + 3 sage: u*a + v*b == g True
The base ring must be a field::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (x^2 + t*x + 1) * (x + t) sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) sage: a.right_xgcd(b) Traceback (most recent call last): ... TypeError: the base ring must be a field """ V = self._parent.zero() else:
r""" Return the right gcd of ``self`` and ``other``.
INPUT:
- ``other`` -- a skew 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 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.)
.. NOTE::
Works only if the base ring is a field (otherwise right gcd do not exist in general).
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (x^2 + t*x + 1) * (x + t) sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) sage: a.right_gcd(b) x + t
Specifying ``monic=False``, we *can* get a nonmonic gcd::
sage: a.right_gcd(b,monic=False) (4*t^2 + 4*t + 1)*x + 4*t^2 + 4*t + 3
The base ring need to be a field::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (x^2 + t*x + 1) * (x + t) sage: b = 2 * (x^3 + (t+1)*x^2 + t^2) * (x + t) sage: a.right_gcd(b) Traceback (most recent call last): ... TypeError: the base ring must be a field """ return self
r""" Return the left gcd of ``self`` and ``other``.
INPUT:
- ``other`` -- a skew 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 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.)
.. NOTE::
Works only if two following 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.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) sage: a.left_gcd(b) x + t
Specifying ``monic=False``, we *can* get a nonmonic gcd::
sage: a.left_gcd(b,monic=False) 2*t*x + 4*t + 2
The base ring needs to be a field::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) sage: a.left_gcd(b) Traceback (most recent call last): ... TypeError: the base ring must be a field
And the twist map needs to be bijective::
sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) sage: S.<x> = FR['x',f] sage: a = (x + t) * (x^2 + t*x + 1) sage: b = 2 * (x + t) * (x^3 + (t+1)*x^2 + t^2) 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 Defn: t |--> t^2 """ return self
r""" Return the left lcm of ``self`` and ``other``.
INPUT:
- ``other`` -- a skew 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 `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 extra condition, it is uniquely determined.)
.. NOTE::
Works only if the base ring is a field (otherwise left lcm do not exist in general).
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (x + t^2) * (x + t) sage: b = 2 * (x^2 + t + 1) * (x * t) sage: c = a.left_lcm(b); c x^5 + (2*t^2 + t + 4)*x^4 + (3*t^2 + 4)*x^3 + (3*t^2 + 3*t + 2)*x^2 + (t^2 + t + 2)*x sage: c.is_right_divisible_by(a) True sage: c.is_right_divisible_by(b) True sage: a.degree() + b.degree() == c.degree() + a.right_gcd(b).degree() True
Specifying ``monic=False``, we *can* get a nonmonic gcd::
sage: a.left_lcm(b,monic=False) (t^2 + t)*x^5 + (4*t^2 + 4*t + 1)*x^4 + (t + 1)*x^3 + (t^2 + 2)*x^2 + (3*t + 4)*x
The base ring needs to be a field::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (x + t^2) * (x + t) sage: b = 2 * (x^2 + t + 1) * (x * t) sage: a.left_lcm(b) Traceback (most recent call last): ... TypeError: the base ring must be a field """ raise ZeroDivisionError("division by zero is not valid")
r""" Return the right lcm of ``self`` and ``other``.
INPUT:
- ``other`` -- a skew 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 `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 extra condition, it is uniquely determined.)
.. NOTE::
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 this field is bijective.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (x + t) * (x + t^2) sage: b = 2 * (x + t) * (x^2 + t + 1) sage: c = a.right_lcm(b); c x^4 + (2*t^2 + t + 2)*x^3 + (3*t^2 + 4*t + 1)*x^2 + (3*t^2 + 4*t + 1)*x + t^2 + 4 sage: c.is_left_divisible_by(a) True sage: c.is_left_divisible_by(b) True sage: a.degree() + b.degree() == c.degree() + a.left_gcd(b).degree() True
Specifying ``monic=False``, we *can* get a nonmonic gcd::
sage: a.right_lcm(b,monic=False) 2*t*x^4 + (3*t + 1)*x^3 + (4*t^2 + 4*t + 3)*x^2 + (3*t^2 + 4*t + 2)*x + 3*t^2 + 2*t + 3
The base ring needs to be a field::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (x + t) * (x + t^2) sage: b = 2 * (x + t) * (x^2 + t + 1) sage: a.right_lcm(b) Traceback (most recent call last): ... TypeError: the base ring must be a field
And the twist map needs to be bijective::
sage: FR = R.fraction_field() sage: f = FR.hom([FR(t)^2]) sage: S.<x> = FR['x',f] sage: a = (x + t) * (x + t^2) sage: b = 2 * (x + t) * (x^2 + t + 1) 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 Defn: t |--> t^2 """ raise ZeroDivisionError("division by zero is not valid")
def _repr_(self, name=None): r""" Return string representation of this skew polynomial.
INPUT:
- ``name`` -- the name of the variable (default: the name given when the skew polynomial ring was created)
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t^2 + 1/2*x*t; sage: a._repr_() '(1/2*t + 1/2)*x + t^2' sage: a._repr_(name='y') '(1/2*t + 1/2)*y + t^2' """ else:
def _latex_(self, name=None): r""" Return a latex representation of this skew polynomial.
INPUT:
- ``name`` -- the name of the variable (default: the name given when the skew polynomial ring was created)
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t^2 + 1/2*x*t; sage: a._latex_() '\\left(\\frac{1}{2} t + \\frac{1}{2}\\right) x + t^{2}' sage: a._latex_(name='y') '\\left(\\frac{1}{2} t + \\frac{1}{2}\\right) y + t^{2}' """ y = y[1:] var = "|%s^{%s}"%(name,n) else: return "0"
def _is_atomic(self): r""" Check ``self`` is a single monomial whose leading coefficient is atomic in the base ring.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: S([t+1])._is_atomic() False sage: S([1])._is_atomic() True """
def __nonzero__(self): r""" Test whether ``self`` is nonzero.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + 1 sage: bool(a) True sage: b = S.zero() sage: bool(b) False """
def base_ring(self): r""" Return the base ring of ``self``.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = S.random_element() sage: a.base_ring() Univariate Polynomial Ring in t over Integer Ring sage: a.base_ring() is R True """
def shift(self, n): r""" Return ``self`` multiplied on the right by the power `x^n`.
If `n` is negative, terms below `x^n` will be discarded.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^5 + t^4*x^4 + t^2*x^2 + t^10 sage: a.shift(0) x^5 + t^4*x^4 + t^2*x^2 + t^10 sage: a.shift(-1) x^4 + t^4*x^3 + t^2*x sage: a.shift(-5) 1 sage: a.shift(2) x^7 + t^4*x^6 + t^2*x^4 + t^10*x^2
One can also use the infix shift operator::
sage: a >> 2 x^3 + t^4*x^2 + t^2 sage: a << 2 x^7 + t^4*x^6 + t^2*x^4 + t^10*x^2 """ return self._parent([]) else:
def __lshift__(self, k): r""" Return ``self`` multiplied on the right by the power `x^k`.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^5 + t^4*x^4 + t^2*x^2 + t^10 sage: a << 2 x^7 + t^4*x^6 + t^2*x^4 + t^10*x^2 """
def __rshift__(self, k): r""" Return ``self`` multiplied on the right by the power `x^(-k)`.
If `n` is negative, terms below `x^n` will be discarded.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^5 + t^4*x^4 + t^2*x^2 + t^10 sage: a >> 2 x^3 + t^4*x^2 + t^2 """
def change_variable_name(self, var): 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.
INPUT:
- ``var`` -- the name of the new variable
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x', sigma] sage: a = x^3 + (2*t + 1)*x + t^2 + 3*t + 5 sage: b = a.change_variable_name('y'); b y^3 + (2*t + 1)*y + t^2 + 3*t + 5
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 twisted by t |--> t + 1 """
def is_term(self): r""" Return ``True`` if ``self`` is an element of the base ring times a power of the generator.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: x.is_term() True sage: R(1).is_term() True sage: (3*x^5).is_term() True sage: (1+3*x^5).is_term() False
If you want to test that ``self`` also has leading coefficient 1, use :meth:`is_monomial()` instead::
sage: (3*x^5).is_monomial() False """
def is_monomial(self): r""" Return ``True`` if ``self`` is a monomial, i.e., a power of the generator.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: x.is_monomial() True sage: (x+1).is_monomial() False sage: (x^2).is_monomial() True sage: S(1).is_monomial() True
The coefficient must be 1::
sage: (2*x^5).is_monomial() False sage: S(t).is_monomial() False
To allow a non-1 leading coefficient, use is_term()::
sage: (2*x^5).is_term() True sage: S(t).is_term() True """
cpdef list coefficients(self, sparse=True): r""" Return the coefficients of the monomials appearing in ``self``.
If ``sparse=True`` (the default), return only the non-zero coefficients. Otherwise, return the same value as ``self.list()``.
.. NOTE::
This should be overridden in subclasses.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: a.coefficients() [t^2 + 1, t + 1, 1] sage: a.coefficients(sparse=False) [t^2 + 1, 0, t + 1, 0, 1] """ raise NotImplementedError
def number_of_terms(self): r""" Return the number of non-zero coefficients of ``self``.
This is also known as the weight, hamming weight or sparsity.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: a.number_of_terms() 3
This is also an alias for ``hamming_weight``::
sage: a.hamming_weight() 3 """
# alias hamming_weight for number_of_terms:
def __copy__(self): r""" Return a "copy" of ``self``.
In Sage, since skew polynomials are immutable, this just returns ``self`` again.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: b = copy(a) sage: b is a True """
cpdef bint is_zero(self): r""" Return ``True`` if ``self`` is the zero polynomial.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + 1 sage: a.is_zero() False sage: b = S.zero() sage: b.is_zero() True """
cpdef bint is_one(self): r""" Test whether this polynomial is `1`.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: R(1).is_one() True sage: (x + 3).is_one() False """
r""" Return the remainder of right division of ``self`` by ``other``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + t*x^2 sage: b = x + 1 sage: a % b t + 1 sage: (x^3 + x - 1).right_mod(x^2 - 1) 2*x - 1 """
r""" Return the remainder of left division of ``self`` by ``other``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = 1 + t*x^2 sage: b = x + 1 sage: a.left_mod(b) 2*t^2 + 4*t """
def is_constant(self): r""" Return whether ``self`` is a constant polynomial.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: R(2).is_constant() True sage: (x + 1).is_constant() False """
def exponents(self): r""" Return the exponents of the monomials appearing in ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: a.exponents() [0, 2, 4] """
def prec(self): r""" Return the precision of ``self``.
This is always infinity, since polynomials are of infinite precision by definition (there is no big-oh).
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: x.prec() +Infinity """
def padded_list(self, n=None): r""" Return list of coefficients of ``self`` up to (but not including) degree `n`.
Includes `0`s in the list on the right so that the list always has length exactly `n`.
INPUT:
- ``n`` -- (default: ``None``); if given, an integer that is at least `0`
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + t*x^3 + t^2*x^5 sage: a.padded_list() [1, 0, 0, t, 0, t^2] sage: a.padded_list(10) [1, 0, 0, t, 0, t^2, 0, 0, 0, 0] sage: len(a.padded_list(10)) 10 sage: a.padded_list(3) [1, 0, 0] sage: a.padded_list(0) [] sage: a.padded_list(-1) Traceback (most recent call last): ... ValueError: n must be at least 0 """ else:
def variable_name(self): r""" Return the string name of the variable used in ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + t sage: a.variable_name() 'x' """
def multi_point_evaluation(self, eval_pts): """ Evaluate ``self`` at list of evaluation points.
INPUT:
- ``eval_pts`` -- list of points at which ``self`` is to be evaluated
OUTPUT:
List of values of ``self`` at the ``eval_pts``.
.. TODO::
This method currently trivially calls the evaluation function repeatedly. If fast skew polynomial multiplication is available, an asymptotically faster method is possible using standard divide and conquer techniques and :meth:`sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_general.minimal_vanishing_polynomial`.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: eval_pts = [1, t, t^2] sage: c = a.multi_point_evaluation(eval_pts); c [t + 1, 3*t^2 + 4*t + 4, 4*t] sage: c == [ a(e) for e in eval_pts ] True """
cdef class SkewPolynomial_generic_dense(SkewPolynomial): r""" Generic implementation of dense skew polynomial supporting any valid base ring and twist map. """
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 coefficients.
INPUT:
- ``parent`` -- parent of ``self``
- ``x`` -- list of coefficients from which ``self`` can be constructed
- ``check`` -- flag variable to normalize the polynomial
- ``construct`` -- boolean (default: ``False``)
TESTS::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma]
We create a skew polynomial from a list::
sage: S([t,1]) x + t
from another skew polynomial::
sage: S(x^2 + t) x^2 + t
from a constant::
sage: x = S(t^2 + 1); x t^2 + 1 sage: x.parent() is S True """ self._coeffs = [] return
else:
if (<Element>x)._parent is self._parent: x = list(x.list()) elif R.has_coerce_map_from((<Element>x)._parent): try: if x.is_zero(): self._coeffs = [] return except (AttributeError, TypeError): pass x = [x] else: self._coeffs = [R(a, **kwds) for a in x.list()] if check: self.__normalize() return
self._coeffs = [] return
x = _dict_to_list(x, R.zero())
else: self._coeffs = x
def __reduce__(self): r""" Return the generic dense skew polynomial corresponding to the current parameters provided ``self``.
EXAMPLES:
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: loads(dumps(x)) == x True sage: loads(dumps(x)) x """
cdef long _hash_c(self): r""" This hash incorporates the name of the variable.
.. NOTE::
This is an internal method. Use :meth:`__hash__` instead. """ #todo - come up with a way to create hashes of zero that # that do not incorrectly indicate that the element is 0. cdef long result_mon cdef long c_hash cdef int i else: return -2
cpdef _richcmp_(left, right, int op): r""" Compare the two skew polynomials ``self`` and ``other``.
We order polynomials first by degree, then in dictionary order starting with the coefficient of largest degree.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: b = (2*t^2)*x + t + 1 sage: a > b True sage: a < b False """
def __iter__(self): r""" Iterate over the list of coefficients of ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: P = S([1, 2, 3]) sage: [y for y in iter(P)] [1, 2, 3] """
def __getitem__(self, n): r""" Return the `n`-th coefficient of ``self``.
INPUT:
- ``n`` -- an integer
OUTPUT:
- the ``n``-th coefficient of ``self``
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x^2 + (t + 3/7)*x + t^2 sage: a[1] t + 3/7 sage: a[3] 0 """
cpdef list list(self, bint copy=True): r""" Return a list of the coefficients of ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: l = a.list(); l [t^2 + 1, 0, t + 1, 0, 1]
Note that `l` is a list, it is mutable, and each call to the list method returns a new list::
sage: type(l) <... 'list'> sage: l[0] = 5 sage: a.list() [t^2 + 1, 0, t + 1, 0, 1] """ # This creates a shallow copy else: return (<SkewPolynomial_generic_dense>self)._coeffs
cpdef dict dict(self): r""" Return a dictionary representation of ``self``.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2012 + t*x^1006 + t^3 + 2*t sage: a.dict() {0: t^3 + 2*t, 1006: t, 2012: 1} """ cdef int i
cpdef int degree(self): r""" Return the degree of ``self``.
By convention, the zero skew polynomial has degree `-1`.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2 + t*x^3 + t^2*x + 1 sage: a.degree() 3
By convention, the degree of `0` is `-1`::
sage: S(0).degree() -1 """
cpdef _add_(self, right): r""" Add two polynomials.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = S.random_element(monic=True); a x^2 + (-12*t^2 + 1/2*t - 1/95)*x - 1/2*t^2 - 4 sage: b = -S.random_element(monic=True); b -x^2 + (5/2*t - 2/3)*x + 1/4*t^2 - 1/2*t + 1 sage: c = a+b; c (-12*t^2 + 3*t - 193/285)*x - 1/4*t^2 - 1/2*t - 3 sage: c.degree() 1 """ cdef Py_ssize_t i, min
else:
cpdef _sub_(self, right): r""" Subtract polynomial ``right`` from ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = S.random_element(monic=True); a x^2 + (-12*t^2 + 1/2*t - 1/95)*x - 1/2*t^2 - 4 sage: b = S.random_element(monic=True); b x^2 + (-5/2*t + 2/3)*x - 1/4*t^2 + 1/2*t - 1 sage: c = a-b; c (-12*t^2 + 3*t - 193/285)*x - 1/4*t^2 - 1/2*t - 3 sage: c.degree() 1 """ cdef Py_ssize_t i, min cdef RingElement c
else:
cpdef _neg_(self): r""" Return the negative of ``self``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x^2 + x - 3 sage: -a -t*x^2 - x + 3 """
cpdef ModuleElement _lmul_(self, Element right): r""" Multiply ``self`` on the right by scalar.
INPUT:
- ``right`` -- an element of the base ring
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x + t sage: b = t sage: a * b (t + 1)*x + t^2 sage: a * b == b * a False """ return self._parent.zero() cdef Py_ssize_t i
cpdef ModuleElement _rmul_(self, Element left): r""" Multiply ``self`` on the left by scalar.
INPUT:
- ``left`` -- an element of the base ring
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t sage: b = x + t sage: a * b t*x + t^2 sage: a * b == b * a False """ cdef Py_ssize_t i
cpdef _mul_(self, right): r""" Multiply ``self`` on the right by a skew polynomial.
INPUT:
- ``right`` -- a skew polynomial in the same ring as ``self``
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2 + t; a x^2 + t sage: b = x^2 + (t + 1)*x; b x^2 + (t + 1)*x sage: a * b x^4 + (t + 3)*x^3 + t*x^2 + (t^2 + t)*x sage: a * b == b * a False
TESTS::
sage: S(0)*a, (S(0)*a).list() (0, []) """ cdef Py_ssize_t i, k, start, end
cdef SkewPolynomial _new_c(self, list coeffs, Parent P, char check=0): r""" Fast creation of a new skew polynomial given a list of coefficients.
.. WARNING::
The list ``coeffs`` is stored internally in the newly created skew polynomial, so this must not be modified after calling this method.
TESTS::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x^3 + x^4 + (t+1)*x^2 sage: a.truncate(4) #indirect doctest t*x^3 + (t + 1)*x^2 """
cdef void __normalize(self): r""" Remove higher order `0`-coefficients from the representation of ``self``.
TESTS::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = 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 """
def valuation(self): r""" Return the minimal degree of a non-zero monomial of ``self``.
By convention, the zero skew polynomial has valuation `+\infty`.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = x^2 + t*x^3 + t^2*x sage: a.valuation() 1
By convention, the valuation of `0` is `+\infty`::
sage: S(0).valuation() +Infinity """
cdef void _inplace_rmul(self, SkewPolynomial_generic_dense right): r""" Replace ``self`` by ``self*right`` (only for internal use).
TESTS::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: modulus = x^3 + t*x^2 + (t+3)*x - 2 sage: a.left_power_mod(100,modulus) # indirect doctest (4*t^2 + t + 1)*x^2 + (t^2 + 4*t + 1)*x + 3*t^2 + 3*t """ cdef Py_ssize_t i, k, start, end self._coeffs = [ ]
cdef void _inplace_pow(self, Py_ssize_t n): r""" Replace ``self`` by ``self**n`` (only for internal use).
TESTS::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: modulus = x^3 + t*x^2 + (t+3)*x - 2 sage: a.left_power_mod(100,modulus) # indirect doctest (4*t^2 + t + 1)*x^2 + (t^2 + 4*t + 1)*x + 3*t^2 + 3*t """
def truncate(self, n): r""" Return the polynomial resulting from discarding all monomials of degree at least `n`.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = t*x^3 + x^4 + (t+1)*x^2 sage: a.truncate(4) t*x^3 + (t + 1)*x^2 sage: a.truncate(3) (t + 1)*x^2 """
r""" Return the quotient and remainder of the left euclidean division of ``self`` by ``other``.
INPUT:
- ``other`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
- the quotient and the remainder of the left euclidean division of this skew 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.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = (3*t^2 + 3*t + 2)*x^3 + (2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2 sage: b = (3*t^2 + 4*t + 2)*x^2 + (2*t^2 + 4*t + 3)*x + 2*t^2 + t + 1 sage: q,r = a.left_quo_rem(b) sage: a == b*q + r True
In the following example, Sage does not know the inverse of the twist map::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = (-2*t^2 - t + 1)*x^3 + (-t^2 + t)*x^2 + (-12*t - 2)*x - t^2 - 95*t + 1 sage: b = x^2 + (5*t - 6)*x - 4*t^2 + 4*t - 1 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 Defn: t |--> t + 1 """ cdef Py_ssize_t i, j except (ZeroDivisionError, TypeError): raise NotImplementedError("the leading coefficient of the divisor is not invertible")
r""" Return the quotient and remainder of the right euclidean division of ``self`` by ``other``.
INPUT:
- ``other`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
- the quotient and the remainder of the left euclidean division of this skew polynomial by ``other``
.. NOTE::
This will fail if the leading coefficient of the divisor is not a unit.
EXAMPLES::
sage: R.<t> = ZZ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = S.random_element(degree=4); a t^2*x^4 + (-12*t^2 - 2*t - 1)*x^3 + (-95*t^2 + t + 2)*x^2 + (-t^2 + t)*x + 2*t - 8 sage: b = S.random_element(monic=True); b x^2 + (4*t^2 - t - 2)*x - t^2 + t - 1 sage: q,r = a.right_quo_rem(b) sage: a == q*b + r True
The leading coefficient of the divisor need to be invertible::
sage: c = S.random_element(); c (-4*t^2 + t)*x^2 - 2*t^2*x + 5*t^2 - 6*t - 4 sage: a.right_quo_rem(c) Traceback (most recent call last): ... NotImplementedError: the leading coefficient of the divisor is not invertible """ cdef Py_ssize_t i, j " is not invertible")
cpdef left_power_mod(self, exp, modulus): r""" Return the remainder of ``self**exp`` in the left euclidean division by ``modulus``.
INPUT:
- ``exp`` -- an Integer
- ``modulus`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Remainder of ``self**exp`` in the left euclidean division by ``modulus``.
REMARK:
The quotient of the underlying skew polynomial ring by the principal ideal generated by ``modulus`` is in general *not* a ring.
As a consequence, Sage first computes exactly ``self**exp`` and then reduce it modulo ``modulus``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: modulus = x^3 + t*x^2 + (t+3)*x - 2 sage: a.left_power_mod(100,modulus) (4*t^2 + t + 1)*x^2 + (t^2 + 4*t + 1)*x + 3*t^2 + 3*t """ cdef SkewPolynomial_generic_dense r try: exp = Integer(exp) except TypeError: raise TypeError("non-integral exponents not supported")
return self.parent()(self._coeffs[0]**exp) return self.parent().one() return (~self).left_power_mod(-exp, modulus)
P = self.parent() R = P.base_ring() v = [R.zero()]*exp + [R.one()] r = <SkewPolynomial_generic_dense>self._parent(v) else:
cpdef right_power_mod(self, exp, modulus): r""" Return the remainder of ``self**exp`` in the right euclidean division by ``modulus``.
INPUT:
- ``exp`` -- an Integer
- ``modulus`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Remainder of ``self**exp`` in the right euclidean division by ``modulus``.
REMARK:
The quotient of the underlying skew polynomial ring by the principal ideal generated by ``modulus`` is in general *not* a ring.
As a consequence, Sage first computes exactly ``self**exp`` and then reduce it modulo ``modulus``.
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: b = a^10 # short form for ``a._pow_(10)`` sage: b == a*a*a*a*a*a*a*a*a*a True sage: modulus = x^3 + t*x^2 + (t+3)*x - 2 sage: br = a.right_power_mod(10,modulus); br (t^2 + t)*x^2 + (3*t^2 + 1)*x + t^2 + t sage: rq, rr = b.right_quo_rem(modulus) sage: br == rr True sage: a.right_power_mod(100,modulus) (2*t^2 + 3)*x^2 + (t^2 + 4*t + 2)*x + t^2 + 2*t + 1 """ cdef SkewPolynomial_generic_dense r except TypeError: raise TypeError("non-integral exponents not supported")
return self.parent()(self._coeffs[0]**exp) return self.parent().one() return (~self).right_power_mod(-exp, modulus)
else:
def __pow__(self, exp, modulus): r""" Return the remainder of ``self**exp`` in the left euclidean division by ``modulus``.
INPUT:
- ``exp`` -- an Integer
- ``modulus`` -- a skew polynomial in the same ring as ``self``
OUTPUT:
Remainder of ``self**exp`` in the right euclidean division by ``modulus``.
REMARK:
The quotient of the underlying skew polynomial ring by the principal ideal generated by ``modulus`` is in general *not* a ring.
As a consequence, Sage first computes exactly ``self**exp`` and then reduce it modulo ``modulus``.
.. SEEALSO::
:meth:`~sage.rings.polynomial.skew_polynomial_element._pow_`
EXAMPLES::
sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: a = x + t sage: b = a^10 sage: b == a*a*a*a*a*a*a*a*a*a True sage: modulus = x^3 + t*x^2 + (t+3)*x - 2 sage: bmod = a.right_power_mod(10,modulus); bmod (t^2 + t)*x^2 + (3*t^2 + 1)*x + t^2 + t sage: rq, rr = b.right_quo_rem(modulus) sage: bmod == rr True """
cpdef list coefficients(self, sparse=True): r""" Return the coefficients of the monomials appearing in ``self``.
If ``sparse=True`` (the default), return only the non-zero coefficients. Otherwise, return the same value as ``self.list()``.
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: a = 1 + x^4 + (t+1)*x^2 + t^2 sage: a.coefficients() [t^2 + 1, t + 1, 1] sage: a.coefficients(sparse=False) [t^2 + 1, 0, t + 1, 0, 1] """ else:
cdef class ConstantSkewPolynomialSection(Map): r""" Representation of the canonical homomorphism from the constants of a skew polynomial ring to the base ring.
This class is necessary for automatic coercion from zero-degree skew polynomial ring into the base ring.
EXAMPLES::
sage: from sage.rings.polynomial.skew_polynomial_element import ConstantSkewPolynomialSection sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: m = ConstantSkewPolynomialSection(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 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.
TESTS::
sage: from sage.rings.polynomial.skew_polynomial_element import ConstantSkewPolynomialSection sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: m = ConstantSkewPolynomialSection(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 To: Univariate Polynomial Ring in t over Rational Field sage: m(S([0,1])-S([0,1])) 0 sage: m(S([3,1])-S([0,1])) 3 sage: m(S([0,1])-S([0,t])) Traceback (most recent call last): ... TypeError: not a constant polynomial """ except AttributeError: return <Element>((<SkewPolynomial>x).constant_coefficient()) else:
cdef class SkewPolynomialBaseringInjection(Morphism): r""" Representation of the canonical homomorphism from a ring `R` into a skew polynomial ring over `R`.
This class is necessary for automatic coercion from the base ring to the skew polynomial ring.
.. SEEALSO::
:class:`~sage.rings.polynomial.polynomial_element.PolynomialBaseringInjection`
EXAMPLES::
sage: R.<t> = QQ[] sage: sigma = R.hom([t+1]) sage: S.<x> = R['x',sigma] sage: S.coerce_map_from(S.base_ring()) #indirect doctest Skew 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 """
def __init__(self, domain, codomain): r""" Construct a Skew Polynomial Basering Injection.
INPUT:
- ``domain`` -- a ring `R`. This will be the domain of the injection.
- ``codomain`` -- a skew polynomial ring over ``domain``. This will be the codomain.
TESTS::
sage: from sage.rings.polynomial.skew_polynomial_element import SkewPolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: SkewPolynomialBaseringInjection(k, k['x', Frob]) Skew 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 sage: R.<t> = QQ[] sage: SkewPolynomialBaseringInjection(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 """ "the domain of the injection must be the base ring of the skew polynomial ring"
def an_element(self): r""" Return an element of the codomain of the ring homomorphism.
EXAMPLES::
sage: from sage.rings.polynomial.skew_polynomial_element import SkewPolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: m = SkewPolynomialBaseringInjection(k, k['x', Frob]) sage: m.an_element() x """
cpdef Element _call_(self, e): r""" Return the corresponding skew polynomial to the element from the base ring according to ``self``.
INPUT:
- ``e`` -- element belonging to the base ring according to ``self``
OUTPUT:
The skew polynomial corresponding to `e` according to ``self``.
TESTS::
sage: from sage.rings.polynomial.skew_polynomial_element import SkewPolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: m = SkewPolynomialBaseringInjection(k, k['x', Frob]) 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 """ except AttributeError: return self._codomain(e)
def section(self): r""" Return the canonical homomorphism from the constants of a skew polynomial ring to the base ring according to ``self``.
TESTS::
sage: from sage.rings.polynomial.skew_polynomial_element import SkewPolynomialBaseringInjection sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob] sage: m = SkewPolynomialBaseringInjection(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 To: Finite Field in t of size 5^3 """ |