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: sage.structure.unique_representation.UniqueRepresentation, sage.rings.ring.Algebra

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: k.<a> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S = OrePolynomialRing(k, Frob, 'x')
sage: S
Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5

In particular, observe that it is not needed to create and pass in the twisting derivation (which is \(0\) in our example).

As a shortcut, we can use the square brackets notation as follow:

sage: T.<x> = k['x', Frob]
sage: T
Ore Polynomial Ring in x over Finite Field in a of size 5^3 twisted by a |--> a^5
sage: T is S
True

We emphasize that it is necessary to repeat the name of the variable in the right hand side. Indeed, the following fails (it is interpreted by Sage as a classical polynomial ring with variable name Frob):

sage: T.<x> = k[Frob]
Traceback (most recent call last):
...
ValueError: variable name 'Frobenius endomorphism a |--> a^5 on Finite Field in a of size 5^3' is not alphanumeric

Note moreover that, similarly to the classical case, using the brackets notation also sets the variable:

sage: x.parent() is S
True

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

sage: x*a
(2*a^2 + 4*a + 4)*x
sage: Frob(a)*x
(2*a^2 + 4*a + 4)*x

The case of a twisting derivation

We can similarly create the Ore ring of differential operators over \(\QQ[t]\), namely \(\QQ[t][d, \frac{d}{dt}]\):

sage: R.<t> = QQ[]
sage: der = R.derivation(); der
d/dt
sage: A = OrePolynomialRing(R, der, 'd')
sage: A
Ore Polynomial Ring in d over Univariate Polynomial Ring in t over Rational Field twisted by d/dt

Again, the brackets notation is available:

sage: B.<d> = R['d', der]
sage: A is B
True

and computations can be carried out:

sage: d*t
t*d + 1

The combined case

Ore polynomial rings involving at the same time a twisting morphism \(\sigma\) and a twisting \(\sigma\)-derivation can be created as well as follows:

sage: F.<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]
sage: M
Ore Polynomial Ring in X over 3-adic Unramified Extension Field in u
 defined by x^2 + 2*x + 2 twisted by Frob and (3 + O(3^21))*([Frob] - id)

We emphasize that we only need to pass in the twisted derivation as it already contains in it the datum of the twisting endomorphism. Actually, passing in both twisting maps results in an error:

sage: F['X', sigma, der]
Traceback (most recent call last):
...
ValueError: variable name 'Frobenius endomorphism ...' is not alphanumeric

Examples of variable name context

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: 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]
False

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

sage: S is k['x', Frob^2]
False
sage: S is k['x', Frob^3]
False
sage: S is k['x', Frob^4]
True

Todo

  • Sparse Ore Polynomial Ring

  • Multivariate Ore Polynomial Ring

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: 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: 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: 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: y is x
True
sage: S.gen(0)
x

This is also known as the parameter:

sage: S.parameter() is S.gen()
True
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, i.e. if the twisting morphism is the identity and the twisting derivation vanishes.

EXAMPLES:

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: 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()

Return always False since Ore polynomial rings are never fields.

EXAMPLES:

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: 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, which 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: y is x
True
sage: S.gen(0)
x

This is also known as the parameter:

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

Return a random Ore polynomial in this ring.

INPUT:

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

When monic is False, the returned Ore polynomial may have a degree less than degree (it happens when the random leading coefficient is zero). However, if monic is True, this cannot happen:

sage: p = S.random_element(degree=4, monic=True)
sage: p.leading_coefficient() == S.base_ring().one()
True
sage: p.degree() == 4
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
(3*t^2 + 1)*x^4 + (4*t + 2)*x^3 + (4*t + 1)*x^2
 + (t^2 + 3*t + 3)*x + 3*t^2 + 2*t + 2

If the first tuple element is greater than the second, a ValueError is raised:

sage: S.random_element(degree=(5,4))
Traceback (most recent call last):
...
ValueError: first degree argument must be less or equal to the second
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: k.<t> = GF(5^3)
sage: Frob = k.frobenius_endomorphism()
sage: S.<x> = k['x',Frob]
sage: A = S.random_irreducible(); A
x^2 + (4*t^2 + 3*t + 4)*x + 4*t^2 + t
sage: A.is_irreducible()
True
sage: B = S.random_irreducible(degree=3,monic=False); B  # random
(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.is_irreducible()
True
twist_map(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.

This method is deprecated. Use twisting_morphism() instead.

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.twist_map()
...
DeprecationWarning: The method twist_map is deprecated; use twisting_morphism (same semantic) instead
See https://trac.sagemath.org/29629 for details.
Ring endomorphism of Univariate Polynomial Ring in t over Rational Field
  Defn: t |--> t + 1
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: 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: 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: 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