Univariate skew polynomial rings¶
This module provides the
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
SkewPolynomialRing_finite_order
, which is a specialized class for skew polynomial rings over fields equipped with an automorphism of finite order. It inherits fromSkewPolynomialRing
but contains more methods and provides better algorithms.the class
SkewPolynomialRing_finite_field
, which is a specialized class for skew polynomial rings over finite fields.
See also
AUTHOR:
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
- class sage.rings.polynomial.skew_polynomial_ring.SectionSkewPolynomialCenterInjection[source]¶
Bases:
Section
Section of the canonical injection of the center of a skew polynomial ring into this ring.
- class sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialCenterInjection(domain, codomain, embed, order)[source]¶
Bases:
RingHomomorphism
Canonical injection of the center of a skew polynomial ring into this ring.
- section()[source]¶
Return a section of this morphism.
EXAMPLES:
sage: # needs sage.rings.finite_rings sage: k.<a> = GF(5^3) sage: S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) sage: Z = S.center() sage: iota = S.convert_map_from(Z) sage: sigma = iota.section() sage: sigma(x^3) z
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> k = GF(Integer(5)**Integer(3), names=('a',)); (a,) = k._first_ngens(1) >>> S = SkewPolynomialRing(k, k.frobenius_endomorphism(), names=('x',)); (x,) = S._first_ngens(1) >>> Z = S.center() >>> iota = S.convert_map_from(Z) >>> sigma = iota.section() >>> sigma(x**Integer(3)) z
# needs sage.rings.finite_rings k.<a> = GF(5^3) S.<x> = SkewPolynomialRing(k, k.frobenius_endomorphism()) Z = S.center() iota = S.convert_map_from(Z) sigma = iota.section() sigma(x^3)
- class sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing(base_ring, morphism, derivation, name, sparse, category=None)[source]¶
Bases:
OrePolynomialRing
Initialize
self
.INPUT:
base_ring
– a commutative ringtwisting_morphism
– an automorphism of the base ringname
– string or list of strings representing the name of the variables of ringsparse
– boolean (default:False
)category
– a category
EXAMPLES:
sage: R.<t> = ZZ[] sage: sigma = R.hom([t + 1]) sage: S.<x> = SkewPolynomialRing(R,sigma) sage: S.category() Category of algebras over Univariate Polynomial Ring in t over Integer Ring sage: S([1]) + S([-1]) 0 sage: TestSuite(S).run()
>>> from sage.all import * >>> R = ZZ['t']; (t,) = R._first_ngens(1) >>> sigma = R.hom([t + Integer(1)]) >>> S = SkewPolynomialRing(R,sigma, names=('x',)); (x,) = S._first_ngens(1) >>> S.category() Category of algebras over Univariate Polynomial Ring in t over Integer Ring >>> S([Integer(1)]) + S([-Integer(1)]) 0 >>> TestSuite(S).run()
R.<t> = ZZ[] sigma = R.hom([t + 1]) S.<x> = SkewPolynomialRing(R,sigma) S.category() S([1]) + S([-1]) TestSuite(S).run()
- lagrange_polynomial(points)[source]¶
Return the minimal-degree polynomial which interpolates the given points.
More precisely, given \(n\) pairs \((x_1, y_1), \ldots, (x_n, y_n) \in R^2\), where \(R\) is
self.base_ring()
, compute a skew polynomial \(p(x)\) such that \(p(x_i) = y_i\) for each \(i\), under the condition that the \(x_i\) are linearly independent over the fixed field ofself.twisting_morphism()
.If the \(x_i\) are linearly independent over the fixed field of
self.twisting_morphism()
then such a polynomial is guaranteed to exist. Otherwise, it might exist depending on the \(y_i\), but the algorithm used in this implementation does not support that, and so an error is always raised.INPUT:
points
– list of pairs \((x_1, y_1), \ldots, (x_n, y_n)\) of elements of the base ring ofself
; the \(x_i\) should be linearly independent over the fixed field ofself.twisting_morphism()
OUTPUT: the Lagrange polynomial
EXAMPLES:
sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x', Frob] sage: points = [(t, 3*t^2 + 4*t + 4), (t^2, 4*t)] sage: d = S.lagrange_polynomial(points); d x + t sage: R.<t> = ZZ[] sage: sigma = R.hom([t + 1]) sage: T.<x> = R['x', sigma] sage: points = [(1, t^2 + 3*t + 4), (t, 2*t^2 + 3*t + 1), (t^2, t^2 + 3*t + 4)] sage: p = T.lagrange_polynomial(points); p ((-t^4 - 2*t - 3)/-2)*x^2 + (-t^4 - t^3 - t^2 - 3*t - 2)*x + (-t^4 - 2*t^3 - 4*t^2 - 10*t - 9)/-2 sage: p.multi_point_evaluation([1, t, t^2]) == [t^2 + 3*t + 4, 2*t^2 + 3*t + 1, t^2 + 3*t + 4] True
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> k = GF(Integer(5)**Integer(3), names=('t',)); (t,) = k._first_ngens(1) >>> Frob = k.frobenius_endomorphism() >>> S = k['x', Frob]; (x,) = S._first_ngens(1) >>> points = [(t, Integer(3)*t**Integer(2) + Integer(4)*t + Integer(4)), (t**Integer(2), Integer(4)*t)] >>> d = S.lagrange_polynomial(points); d x + t >>> R = ZZ['t']; (t,) = R._first_ngens(1) >>> sigma = R.hom([t + Integer(1)]) >>> T = R['x', sigma]; (x,) = T._first_ngens(1) >>> points = [(Integer(1), t**Integer(2) + Integer(3)*t + Integer(4)), (t, Integer(2)*t**Integer(2) + Integer(3)*t + Integer(1)), (t**Integer(2), t**Integer(2) + Integer(3)*t + Integer(4))] >>> p = T.lagrange_polynomial(points); p ((-t^4 - 2*t - 3)/-2)*x^2 + (-t^4 - t^3 - t^2 - 3*t - 2)*x + (-t^4 - 2*t^3 - 4*t^2 - 10*t - 9)/-2 >>> p.multi_point_evaluation([Integer(1), t, t**Integer(2)]) == [t**Integer(2) + Integer(3)*t + Integer(4), Integer(2)*t**Integer(2) + Integer(3)*t + Integer(1), t**Integer(2) + Integer(3)*t + Integer(4)] True
# needs sage.rings.finite_rings k.<t> = GF(5^3) Frob = k.frobenius_endomorphism() S.<x> = k['x', Frob] points = [(t, 3*t^2 + 4*t + 4), (t^2, 4*t)] d = S.lagrange_polynomial(points); d R.<t> = ZZ[] sigma = R.hom([t + 1]) T.<x> = R['x', sigma] points = [(1, t^2 + 3*t + 4), (t, 2*t^2 + 3*t + 1), (t^2, t^2 + 3*t + 4)] p = T.lagrange_polynomial(points); p p.multi_point_evaluation([1, t, t^2]) == [t^2 + 3*t + 4, 2*t^2 + 3*t + 1, t^2 + 3*t + 4]
If the \(x_i\) are linearly dependent over the fixed field of
self.twisting_morphism()
, then an error is raised: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 twisting morphism, so a Lagrange polynomial could not be determined (and might not exist)
>>> from sage.all import * >>> T.lagrange_polynomial([(t, Integer(1)), (Integer(2)*t, Integer(3))]) Traceback (most recent call last): ... 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)
T.lagrange_polynomial([(t, 1), (2*t, 3)])
- minimal_vanishing_polynomial(eval_pts)[source]¶
Return the minimal-degree, monic skew polynomial which vanishes at all the given evaluation points.
The degree of the vanishing polynomial is at most the length of
eval_pts
. Equality holds if and only if the elements ofeval_pts
are linearly independent over the fixed field ofself.twisting_morphism()
.eval_pts
– list of evaluation points which are linearly independent over the fixed field of the twisting morphism of the associated skew polynomial ring
OUTPUT: the minimal vanishing polynomial
EXAMPLES:
sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x', Frob] sage: eval_pts = [1, t, t^2] sage: b = S.minimal_vanishing_polynomial(eval_pts); b x^3 + 4
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> k = GF(Integer(5)**Integer(3), names=('t',)); (t,) = k._first_ngens(1) >>> Frob = k.frobenius_endomorphism() >>> S = k['x', Frob]; (x,) = S._first_ngens(1) >>> eval_pts = [Integer(1), t, t**Integer(2)] >>> b = S.minimal_vanishing_polynomial(eval_pts); b x^3 + 4
# needs sage.rings.finite_rings k.<t> = GF(5^3) Frob = k.frobenius_endomorphism() S.<x> = k['x', Frob] eval_pts = [1, t, t^2] b = S.minimal_vanishing_polynomial(eval_pts); b
The minimal vanishing polynomial evaluates to 0 at each of the evaluation points:
sage: eval = b.multi_point_evaluation(eval_pts); eval # needs sage.rings.finite_rings [0, 0, 0]
>>> from sage.all import * >>> eval = b.multi_point_evaluation(eval_pts); eval # needs sage.rings.finite_rings [0, 0, 0]
eval = b.multi_point_evaluation(eval_pts); eval # needs sage.rings.finite_rings
If the evaluation points are linearly dependent over the fixed field of the twisting morphism, then the returned polynomial has lower degree than the number of evaluation points:
sage: S.minimal_vanishing_polynomial([t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t sage: S.minimal_vanishing_polynomial([t, 3*t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t
>>> from sage.all import * >>> S.minimal_vanishing_polynomial([t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t >>> S.minimal_vanishing_polynomial([t, Integer(3)*t]) # needs sage.rings.finite_rings x + 3*t^2 + 3*t
S.minimal_vanishing_polynomial([t]) # needs sage.rings.finite_rings S.minimal_vanishing_polynomial([t, 3*t]) # needs sage.rings.finite_rings
- class sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_field(base_ring, morphism, derivation, names, sparse, category=None)[source]¶
Bases:
SkewPolynomialRing_finite_order
A specialized class for skew polynomial rings over finite fields.
See also
Todo
Add methods related to center of skew polynomial ring, irreducibility, karatsuba multiplication and factorization.
- class sage.rings.polynomial.skew_polynomial_ring.SkewPolynomialRing_finite_order(base_ring, morphism, derivation, name, sparse, category=None)[source]¶
Bases:
SkewPolynomialRing
A specialized class for skew polynomial rings whose twising morphism has finite order.
See also
- center(name=None, names=None, default=False)[source]¶
Return the center of this skew polynomial ring.
Note
If \(F\) denotes the subring of \(R\) fixed by \(\sigma\) and \(\sigma\) has order \(r\), the center of \(K[x,\sigma]\) is \(F[x^r]\), that is a univariate polynomial ring over \(F\).
INPUT:
name
– string orNone
(default:None
); the name for the central variable (namely \(x^r\))default
– boolean (default:False
); ifTrue
, set the default variable name for the center toname
EXAMPLES:
sage: # needs sage.rings.finite_rings sage: k.<t> = GF(5^3) sage: Frob = k.frobenius_endomorphism() sage: S.<x> = k['x',Frob]; S 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 sage: Z.gen() z
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> k = GF(Integer(5)**Integer(3), names=('t',)); (t,) = k._first_ngens(1) >>> Frob = k.frobenius_endomorphism() >>> S = k['x',Frob]; (x,) = S._first_ngens(1); S Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 >>> Z = S.center(); Z Univariate Polynomial Ring in z over Finite Field of size 5 >>> Z.gen() z
# needs sage.rings.finite_rings k.<t> = GF(5^3) Frob = k.frobenius_endomorphism() S.<x> = k['x',Frob]; S Z = S.center(); Z Z.gen()
We can pass in another variable name:
sage: S.center(name='y') # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5
>>> from sage.all import * >>> S.center(name='y') # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5
S.center(name='y') # needs sage.rings.finite_rings
or use the bracket notation:
sage: Zy.<y> = S.center(); Zy # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5 sage: y.parent() is Zy # needs sage.rings.finite_rings True
>>> from sage.all import * >>> Zy = S.center(names=('y',)); (y,) = Zy._first_ngens(1); Zy # needs sage.rings.finite_rings Univariate Polynomial Ring in y over Finite Field of size 5 >>> y.parent() is Zy # needs sage.rings.finite_rings True
Zy.<y> = S.center(); Zy # needs sage.rings.finite_rings y.parent() is Zy # needs sage.rings.finite_rings
A coercion map from the center to the skew polynomial ring is set:
sage: # needs sage.rings.finite_rings sage: S.has_coerce_map_from(Zy) True sage: P = y + x; P x^3 + x sage: P.parent() 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
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> S.has_coerce_map_from(Zy) True >>> P = y + x; P x^3 + x >>> P.parent() Ore Polynomial Ring in x over Finite Field in t of size 5^3 twisted by t |--> t^5 >>> P.parent() is S True
# needs sage.rings.finite_rings S.has_coerce_map_from(Zy) P = y + x; P P.parent() P.parent() is S
together with a conversion map in the reverse direction:
sage: Zy(x^6 + 2*x^3 + 3) # needs sage.rings.finite_rings y^2 + 2*y + 3 sage: Zy(x^2) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: x^2 is not in the center
>>> from sage.all import * >>> Zy(x**Integer(6) + Integer(2)*x**Integer(3) + Integer(3)) # needs sage.rings.finite_rings y^2 + 2*y + 3 >>> Zy(x**Integer(2)) # needs sage.rings.finite_rings Traceback (most recent call last): ... ValueError: x^2 is not in the center
Zy(x^6 + 2*x^3 + 3) # needs sage.rings.finite_rings Zy(x^2) # needs sage.rings.finite_rings
Two different skew polynomial rings can share the same center:
sage: S1.<x1> = k['x1', Frob] # needs sage.rings.finite_rings sage: S2.<x2> = k['x2', Frob] # needs sage.rings.finite_rings sage: S1.center() is S2.center() # needs sage.rings.finite_rings True
>>> from sage.all import * >>> S1 = k['x1', Frob]; (x1,) = S1._first_ngens(1)# needs sage.rings.finite_rings >>> S2 = k['x2', Frob]; (x2,) = S2._first_ngens(1)# needs sage.rings.finite_rings >>> S1.center() is S2.center() # needs sage.rings.finite_rings True
S1.<x1> = k['x1', Frob] # needs sage.rings.finite_rings S2.<x2> = k['x2', Frob] # needs sage.rings.finite_rings S1.center() is S2.center() # needs sage.rings.finite_rings
About the default name of the central variable
A priori, the default is
z
.However, a variable name is given the first time this method is called, the given name become the default for the next calls:
sage: # needs sage.rings.finite_rings sage: K.<t> = GF(11^3) sage: phi = K.frobenius_endomorphism() sage: A.<X> = K['X', phi] sage: C.<u> = A.center() # first call sage: C Univariate Polynomial Ring in u over Finite Field of size 11 sage: A.center() # second call: the variable name is still u Univariate Polynomial Ring in u over Finite Field of size 11 sage: A.center() is C True
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> K = GF(Integer(11)**Integer(3), names=('t',)); (t,) = K._first_ngens(1) >>> phi = K.frobenius_endomorphism() >>> A = K['X', phi]; (X,) = A._first_ngens(1) >>> C = A.center(names=('u',)); (u,) = C._first_ngens(1)# first call >>> C Univariate Polynomial Ring in u over Finite Field of size 11 >>> A.center() # second call: the variable name is still u Univariate Polynomial Ring in u over Finite Field of size 11 >>> A.center() is C True
# needs sage.rings.finite_rings K.<t> = GF(11^3) phi = K.frobenius_endomorphism() A.<X> = K['X', phi] C.<u> = A.center() # first call C A.center() # second call: the variable name is still u A.center() is C
We can update the default variable name by passing in the argument
default=True
:sage: # needs sage.rings.finite_rings sage: D.<v> = A.center(default=True) sage: D Univariate Polynomial Ring in v over Finite Field of size 11 sage: A.center() Univariate Polynomial Ring in v over Finite Field of size 11 sage: A.center() is D True
>>> from sage.all import * >>> # needs sage.rings.finite_rings >>> D = A.center(default=True, names=('v',)); (v,) = D._first_ngens(1) >>> D Univariate Polynomial Ring in v over Finite Field of size 11 >>> A.center() Univariate Polynomial Ring in v over Finite Field of size 11 >>> A.center() is D True
# needs sage.rings.finite_rings D.<v> = A.center(default=True) D A.center() A.center() is D