Univariate Ore polynomial rings#

This module provides the 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)

class sage.rings.polynomial.ore_polynomial_ring.OrePolynomialRing(base_ring, morphism, derivation, name, sparse, category=None)#

Bases: UniqueRepresentation, Parent

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 \(\GF{5^3}[x, \text{Frob}]\) where Frob is the Frobenius endomorphism:

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S = OrePolynomialRing(k, Frob, 'x'); 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: # needs sage.rings.finite_rings
sage: T.<x> = k['x', Frob]; 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.<x> = k[Frob]                                                           # needs sage.rings.finite_rings
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                                                           # needs sage.rings.finite_rings
True

We are now ready to carry on computations in the Ore ring:

sage: x*a                                                                       # needs sage.rings.finite_rings
(2*a^2 + 4*a + 4)*x
sage: Frob(a)*x                                                                 # needs sage.rings.finite_rings
(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: # needs sage.rings.finite_rings
sage: R.<t> = QQ[]
sage: der = R.derivation(); der
d/dt
sage: A = OrePolynomialRing(R, der, 'd'); 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.<d> = R['d', der]                                                       # needs sage.rings.finite_rings
sage: A is B                                                                    # needs sage.rings.finite_rings
True

and computations can be carried out:

sage: d*t                                                                       # needs sage.rings.finite_rings
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: # needs sage.rings.padics
sage: F.<u> = 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.<X> = F['X', der]; 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]                                                        # needs sage.rings.padics
Traceback (most recent call last):
...
ValueError: variable name 'Frobenius endomorphism ...' is not alphanumeric

Examples of variable name context

Consider the following:

sage: R.<t> = ZZ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = 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: R.<t> = ZZ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = SkewPolynomialRing(R, sigma); S
Ore Polynomial Ring in x over Univariate Polynomial Ring in t over Integer Ring
 twisted by t |--> t + 1

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: # needs sage.rings.finite_rings
sage: k.<a> = 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]                                                         # needs sage.rings.finite_rings
False

Similarly, varying the twisting morphisms yields to different Ore rings (expect when the morphism coincide):

sage: S is k['x', Frob^2]                                                       # needs sage.rings.finite_rings
False
sage: S is k['x', Frob^3]                                                       # needs sage.rings.finite_rings
False
sage: S is k['x', Frob^4]                                                       # needs sage.rings.finite_rings
True

Todo

  • Sparse Ore Polynomial Ring

  • Multivariate Ore Polynomial Ring

Element = None#
change_var(var)#

Return the Ore polynomial ring in variable var with the same base ring, twisting morphism and twisting derivation as self.

INPUT:

  • var – a string representing the name of the new variable

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: k.<t> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: R.<x> = 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
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
characteristic()#

Return the characteristic of the base ring of self.

EXAMPLES:

sage: R.<t> = QQ[]
sage: sigma = R.hom([t+1])
sage: R['x',sigma].characteristic()
0

sage: # needs sage.rings.finite_rings
sage: k.<u> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: k['y',Frob].characteristic()
5
fraction_field()#

Return the fraction field of this skew ring.

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x', Frob]
sage: K = S.fraction_field(); K
Ore Function Field in x over Finite Field in a of size 5^3 twisted by a |--> a^5
sage: f = 1/(x + a); f
(x + a)^(-1)
sage: f.parent() is K
True

Below is another example with differentiel operators:

sage: R.<t> = QQ[]
sage: der = R.derivation()
sage: A.<d> = R['d', der]
sage: A.fraction_field()
Ore Function Field in d over Fraction Field of Univariate Polynomial Ring in t
 over Rational Field twisted by d/dt
sage: f = t/d; f
(d - 1/t)^(-1) * t
sage: f*d
t
gen(n=0)#

Return the indeterminate generator of this Ore polynomial ring.

INPUT:

  • n – index of generator to return (default: 0); exists for compatibility with other polynomial rings

EXAMPLES:

sage: R.<t> = QQ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x',sigma]; S
Ore Polynomial Ring in x over Univariate Polynomial Ring in t
 over Rational Field twisted by t |--> t + 1
sage: y = S.gen(); y
x
sage: y == x
True
sage: S.gen(0)
x

This is also known as the parameter:

sage: S.parameter() is S.gen()
True
gens()#

Return the tuple of generators of self.

EXAMPLES:

sage: R.<t> = QQ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x',sigma]; S
Ore Polynomial Ring in x over Univariate Polynomial Ring in t
 over Rational Field twisted by t |--> t + 1
sage: S.gens()
(x,)
gens_dict()#

Return a {name: variable} dictionary of the generators of this Ore polynomial ring.

EXAMPLES:

sage: R.<t> = ZZ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = SkewPolynomialRing(R,sigma)
sage: S.gens_dict()
{'x': x}
is_commutative()#

Return True if this Ore polynomial ring is commutative.

This holds if the twisting morphism is the identity and the twisting derivation vanishes.

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x', Frob]
sage: S.is_commutative()
False
sage: T.<y> = k['y', Frob^3]
sage: T.is_commutative()
True

sage: R.<t> = GF(5)[]
sage: der = R.derivation()
sage: A.<d> = R['d', der]
sage: A.is_commutative()
False
sage: B.<b> = R['b', 5*der]
sage: B.is_commutative()
True
is_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: # needs sage.rings.finite_rings
sage: k.<t> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x', Frob]
sage: S.is_exact()
True
sage: S.base_ring().is_exact()
True
sage: R.<u> = k[[]]
sage: sigma = R.hom([u + u^2])
sage: T.<y> = R['y', sigma]
sage: T.is_exact()
False
sage: T.base_ring().is_exact()
False
is_field(proof=False)#

Return always False since Ore polynomial rings are never fields.

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x', Frob]
sage: S.is_field()
False
is_finite()#

Return False since Ore polynomial rings are not finite (unless the base ring is \(0\)).

EXAMPLES:

sage: # needs sage.rings.finite_rings
sage: k.<t> = GF(5^3)
sage: k.is_finite()
True
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x',Frob]
sage: S.is_finite()
False
is_sparse()#

Return True if the elements of this Ore polynomial ring are sparsely represented.

Warning

Since sparse Ore polynomials are not yet implemented, this function always returns False.

EXAMPLES:

sage: R.<t> = RR[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x',sigma]
sage: S.is_sparse()
False
ngens()#

Return the number of generators of this Ore polynomial ring.

This is \(1\).

EXAMPLES:

sage: R.<t> = RR[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x',sigma]
sage: S.ngens()
1
parameter(n=0)#

Return the indeterminate generator of this Ore polynomial ring.

INPUT:

  • n – index of generator to return (default: 0); exists for compatibility with other polynomial rings

EXAMPLES:

sage: R.<t> = QQ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x',sigma]; S
Ore Polynomial Ring in x over Univariate Polynomial Ring in t
 over Rational Field twisted by t |--> t + 1
sage: y = S.gen(); y
x
sage: y == x
True
sage: S.gen(0)
x

This is also known as the parameter:

sage: S.parameter() is S.gen()
True
random_element(degree=(-1, 2), monic=False, *args, **kwds)#

Return a random Ore polynomial in this ring.

INPUT:

  • degree – (default: (-1,2)) integer with degree or a tuple of integers with minimum and maximum degrees

  • monic – (default: False) if True, return a monic Ore polynomial

  • *args, **kwds – passed on to the random_element method for the base ring

OUTPUT:

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.

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: S.random_element()  # random
(2*t^2 + 3)*x^2 + (4*t^2 + t + 4)*x + 2*t^2 + 2
sage: S.random_element(monic=True)  # random
x^2 + (2*t^2 + t + 1)*x + 3*t^2 + 3*t + 2

Use degree to obtain polynomials of higher degree:

sage: # needs sage.rings.finite_rings
sage: p = S.random_element(degree=5)   # random
(t^2 + 3*t)*x^5 + (4*t + 4)*x^3 + (4*t^2 + 4*t)*x^2 + (2*t^2 + 1)*x + 3
sage: p.degree() == 5
True

If a tuple of two integers is given for the degree argument, a random integer will be chosen between the first and second element of the tuple as the degree, both inclusive:

sage: S.random_element(degree=(2,7))  # random                              # needs sage.rings.finite_rings
(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
random_irreducible(degree=2, monic=True, *args, **kwds)#

Return a random irreducible Ore polynomial.

Warning

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.

INPUT:

  • degree - Integer with degree (default: 2) or a tuple of integers with minimum and maximum degrees

  • monic - if True, returns a monic Ore polynomial (default: True)

  • *args, **kwds - passed in to the random_element method for the base ring

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: A = S.random_irreducible()
sage: A.is_irreducible()
True
sage: B = S.random_irreducible(degree=3, monic=False)
sage: B.is_irreducible()
True
twisting_derivation()#

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.<t> = QQ[]
sage: der = R.derivation(); der
d/dt
sage: A.<d> = R['d', der]
sage: A.twisting_derivation()
d/dt

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x', Frob]
sage: S.twisting_derivation()
twisting_morphism(n=1)#

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:

  • n - an integer (default: 1)

EXAMPLES:

sage: R.<t> = QQ[]
sage: sigma = R.hom([t+1])
sage: S.<x> = R['x', sigma]
sage: S.twisting_morphism()
Ring endomorphism of Univariate Polynomial Ring in t over Rational Field
  Defn: t |--> t + 1
sage: S.twisting_morphism() == sigma
True
sage: S.twisting_morphism(10)
Ring endomorphism of Univariate Polynomial Ring in t over Rational Field
  Defn: t |--> t + 10

If n in negative, Sage tries to compute the inverse of the twisting morphism:

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: T.<y> = k['y',Frob]
sage: T.twisting_morphism(-1)
Frobenius endomorphism a |--> a^(5^2) on Finite Field in a of size 5^3

Sometimes it fails, even if the twisting morphism is actually invertible:

sage: K = R.fraction_field()
sage: phi = K.hom([(t+1)/(t-1)])
sage: T.<y> = K['y', phi]
sage: T.twisting_morphism(-1)
Traceback (most recent call last):
...
NotImplementedError: inverse not implemented for morphisms of
Fraction Field of Univariate Polynomial Ring in t over Rational Field

When the Ore polynomial ring is only twisted by a derivation, this method returns nothing:

sage: der = R.derivation()
sage: A.<d> = 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 inferred from the derivation:

sage: # needs sage.rings.finite_rings
sage: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: der = k.derivation(1, twist=Frob)
sage: der
[a |--> a^5] - id
sage: S.<x> = k['x', der]
sage: S.twisting_morphism()
Frobenius endomorphism a |--> a^5 on Finite Field in a of size 5^3