Morphisms between Ore modules

Let \(R\) be a commutative ring, \(\theta : R \to R\) by a ring endomorphism and \(\partial : R \to R\) be a \(\theta\)-derivation. Let also \(\mathcal S = R[X; \theta, \partial]\) denote the associated Ore polynomial ring.

By definition, a Ore module is a module over \(\mathcal S\). In SageMath, there are rather represented as modules over \(R\) equipped with the map giving the action of the Ore variable \(X\). We refer to sage.modules.ore_module for more details.

A morphism of Ore modules is a \(R\)-linear morphism commuting with the Ore action, or equivalenty a \(\mathcal S\)-linear map.

Construction of morphisms

There are several ways for creating Ore modules morphisms in SageMath. First of all, one can use the method sage.modules.ore_module.OreModule.hom(), passing to it the matrix (in the canonical bases) of the morphism we want to build:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M.<e0,e1> = S.quotient_module(X^2 + X + z)

sage: mat = matrix(2, 2, [z,     3*z^2 + z + 2,
....:                     z + 1,       4*z + 4])
sage: f = M.hom(mat)
sage: f
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + X + z, names=('e0', 'e1',)); (e0, e1,) = M._first_ngens(2)

>>> mat = matrix(Integer(2), Integer(2), [z,     Integer(3)*z**Integer(2) + z + Integer(2),
...                     z + Integer(1),       Integer(4)*z + Integer(4)])
>>> f = M.hom(mat)
>>> f
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5

Clearly, this method is not optimal: typing all the entries of the defining matrix is long and a potential source of errors.

Instead, one can use a dictionary encoding the values taken by the morphism on a set of generators; the morphism is then automatically prolonged by \(\mathcal S\)-linearity. Actually here, \(f\) was just the multiplication by \(X^3\) on \(M\). We can then redefine it simply as follows:

sage: g = M.hom({e0: X^3*e0})
sage: g
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> g = M.hom({e0: X**Integer(3)*e0})
>>> g
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5

One can then recover the matrix by using the method sage.modules.ore_module_morphism.OreModuleMorphism.matrix():

sage: g.matrix()
[            z 3*z^2 + z + 2]
[        z + 1       4*z + 4]
>>> from sage.all import *
>>> g.matrix()
[            z 3*z^2 + z + 2]
[        z + 1       4*z + 4]

Alternatively, one can use the method sage.modules.ore_module.OreModule.multiplication_map():

sage: h = M.multiplication_map(X^3)
sage: h
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: g == h
True
>>> from sage.all import *
>>> h = M.multiplication_map(X**Integer(3))
>>> h
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> g == h
True

Of course, this method also accepts values in the base ring:

sage: h = M.multiplication_map(2)
sage: h
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: h.matrix()
[2 0]
[0 2]
>>> from sage.all import *
>>> h = M.multiplication_map(Integer(2))
>>> h
Ore module endomorphism of Ore module <e0, e1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> h.matrix()
[2 0]
[0 2]

Be careful that scalar multiplications do not always properly define a morphism of Ore modules:

sage: M.multiplication_map(z)
Traceback (most recent call last):
...
ValueError: does not define a morphism of Ore modules
>>> from sage.all import *
>>> M.multiplication_map(z)
Traceback (most recent call last):
...
ValueError: does not define a morphism of Ore modules

SageMath provides methods to compute kernels, cokernels, images and coimages. In order to illustrate this, we will build the sequence

\[0 \to \mathcal S/ \mathcal S P \to \mathcal S/ \mathcal S PQ \to \mathcal S/ \mathcal S Q \to 0\]

and check that it is exact. We first build the Ore modules:

sage: P = X^2 + z*X + 1
sage: Q = X^3 + z^2*X^2 + X + z
sage: U = S.quotient_module(P, names='u')
sage: U.inject_variables()
Defining u0, u1
sage: V = S.quotient_module(P*Q, names='v')
sage: V.inject_variables()
Defining v0, v1, v2, v3, v4
sage: W = S.quotient_module(Q, names='w')
sage: W.inject_variables()
Defining w0, w1, w2
>>> from sage.all import *
>>> P = X**Integer(2) + z*X + Integer(1)
>>> Q = X**Integer(3) + z**Integer(2)*X**Integer(2) + X + z
>>> U = S.quotient_module(P, names='u')
>>> U.inject_variables()
Defining u0, u1
>>> V = S.quotient_module(P*Q, names='v')
>>> V.inject_variables()
Defining v0, v1, v2, v3, v4
>>> W = S.quotient_module(Q, names='w')
>>> W.inject_variables()
Defining w0, w1, w2

Next, we build the morphisms:

sage: f = U.hom({u0: Q*v0})
sage: g = V.hom({v0: w0})
>>> from sage.all import *
>>> f = U.hom({u0: Q*v0})
>>> g = V.hom({v0: w0})

We can now check that \(f\) is injective by computing its kernel:

sage: f.kernel()
Ore module of rank 0 over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> f.kernel()
Ore module of rank 0 over Finite Field in z of size 5^3 twisted by z |--> z^5

We see on the output that it has dimension \(0\); so it vanishes. Instead of reading the output, one can check programmatically the vanishing of a Ore module using the method sage.modules.ore_module.OreModule.is_zero():

sage: f.kernel().is_zero()
True
>>> from sage.all import *
>>> f.kernel().is_zero()
True

Actually, in our use case, one can, more simply, use the method sage.modules.ore_module_morphism.OreModuleMorphism.is_injective():

sage: f.is_injective()
True
>>> from sage.all import *
>>> f.is_injective()
True

Similarly, one checks that \(g\) is surjective:

sage: g.is_surjective()
True
>>> from sage.all import *
>>> g.is_surjective()
True

or equivalently:

sage: g.cokernel().is_zero()
True
>>> from sage.all import *
>>> g.cokernel().is_zero()
True

Now, we need to check that the kernel of \(g\) equals the image of \(f\). For this, we compute both and compare the results:

sage: ker = g.kernel()
sage: im = f.image()
sage: ker == im
True
>>> from sage.all import *
>>> ker = g.kernel()
>>> im = f.image()
>>> ker == im
True

As a sanity check, one can also verity that the composite \(g \circ f\) vanishes:

sage: h = g * f
sage: h
Ore module morphism:
  From: Ore module <u0, u1> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <w0, w1, w2> over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: h.is_zero()
True
>>> from sage.all import *
>>> h = g * f
>>> h
Ore module morphism:
  From: Ore module <u0, u1> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <w0, w1, w2> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> h.is_zero()
True

Let us now consider another morphism \(f\) and build the canonical isomorphism \(\text{coim }f \to \text{im }f\) that it induces. We start by defining \(f\):

sage: A = X + z
sage: B = X + z + 1
sage: P = X^2 + X + z
sage: U = S.quotient_module(B*P, names='u')
sage: U.inject_variables()
Defining u0, u1, u2
sage: V = S.quotient_module(P*A, names='v')
sage: V.inject_variables()
Defining v0, v1, v2

sage: f = U.hom({u0: A*v0})
sage: f
Ore module morphism:
  From: Ore module <u0, u1, u2> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <v0, v1, v2> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> A = X + z
>>> B = X + z + Integer(1)
>>> P = X**Integer(2) + X + z
>>> U = S.quotient_module(B*P, names='u')
>>> U.inject_variables()
Defining u0, u1, u2
>>> V = S.quotient_module(P*A, names='v')
>>> V.inject_variables()
Defining v0, v1, v2

>>> f = U.hom({u0: A*v0})
>>> f
Ore module morphism:
  From: Ore module <u0, u1, u2> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <v0, v1, v2> over Finite Field in z of size 5^3 twisted by z |--> z^5

Now we compute the image and the coimage:

sage: I = f.image(names='im')
sage: I
Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5

sage: C = f.coimage(names='co')
sage: C
Ore module <co0, co1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> I = f.image(names='im')
>>> I
Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5

>>> C = f.coimage(names='co')
>>> C
Ore module <co0, co1> over Finite Field in z of size 5^3 twisted by z |--> z^5

We can already check that the image and the coimage have the same rank. We now want to construct the isomorphism between them. For this, we first need to corestrict \(f\) to its image. This is achieved via the method sage.modules.ore_module.OreSubmodule.morphism_corestriction() of the Ore module:

sage: g = I.morphism_corestriction(f)
sage: g
Ore module morphism:
  From: Ore module <u0, u1, u2> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> g = I.morphism_corestriction(f)
>>> g
Ore module morphism:
  From: Ore module <u0, u1, u2> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5

Next, we want to factor \(g\) by the coimage. We proceed as follows:

sage: h = C.morphism_quotient(g)
sage: h
Ore module morphism:
  From: Ore module <co0, co1> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> from sage.all import *
>>> h = C.morphism_quotient(g)
>>> h
Ore module morphism:
  From: Ore module <co0, co1> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5

We have found the morphism we were looking for: it is \(h\). We can now check that it is an isomorphism:

sage: h.is_isomorphism()
True
>>> from sage.all import *
>>> h.is_isomorphism()
True

As a shortcut, we can use explicit conversions as follows:

sage: H = Hom(C, I)  # the hom space
sage: h2 = H(f)
sage: h2
Ore module morphism:
  From: Ore module <co0, co1> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: h == h2
True
>>> from sage.all import *
>>> H = Hom(C, I)  # the hom space
>>> h2 = H(f)
>>> h2
Ore module morphism:
  From: Ore module <co0, co1> over Finite Field in z of size 5^3 twisted by z |--> z^5
  To:   Ore module <im0, im1> over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> h == h2
True

For endomorphisms, one can compute classical invariants as determinants and characteristic polynomials. To illustrate this, we check on an example that the characteristic polynomial of the multiplication by \(X^3\) on the quotient \(\mathcal S / \mathcal S P\) is the reduced norm of \(P\):

sage: P = X^5 + z*X^4 + z^2*X^2 + z + 1
sage: M = S.quotient_module(P)
sage: f = M.multiplication_map(X^3)
sage: f.charpoly()
x^5 + x^4 + x^3 + x^2 + 1

sage: P.reduced_norm('x')
x^5 + x^4 + x^3 + x^2 + 1
>>> from sage.all import *
>>> P = X**Integer(5) + z*X**Integer(4) + z**Integer(2)*X**Integer(2) + z + Integer(1)
>>> M = S.quotient_module(P)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.charpoly()
x^5 + x^4 + x^3 + x^2 + 1

>>> P.reduced_norm('x')
x^5 + x^4 + x^3 + x^2 + 1

AUTHOR:

  • Xavier Caruso (2024-10)

class sage.modules.ore_module_morphism.OreModuleMorphism(parent, im_gens, check=True)[source]

Bases: Morphism

Generic class for morphism between Ore modules.

characteristic_polynomial(var='x')[source]

Return the determinant of this endomorphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + (z^2 + 3)*X + z^5
sage: M = S.quotient_module(P)
sage: f = M.multiplication_map(X^3)
sage: f.characteristic_polynomial()
x^3 + x^2 + 2*x + 2
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + (z**Integer(2) + Integer(3))*X + z**Integer(5)
>>> M = S.quotient_module(P)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.characteristic_polynomial()
x^3 + x^2 + 2*x + 2

We check that the latter is equal to the reduced norm of \(P\):

sage: P.reduced_norm('x')
x^3 + x^2 + 2*x + 2
>>> from sage.all import *
>>> P.reduced_norm('x')
x^3 + x^2 + 2*x + 2
charpoly(var='x')[source]

Return the determinant of this endomorphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + (z^2 + 3)*X + z^5
sage: M = S.quotient_module(P)
sage: f = M.multiplication_map(X^3)
sage: f.characteristic_polynomial()
x^3 + x^2 + 2*x + 2
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + (z**Integer(2) + Integer(3))*X + z**Integer(5)
>>> M = S.quotient_module(P)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.characteristic_polynomial()
x^3 + x^2 + 2*x + 2

We check that the latter is equal to the reduced norm of \(P\):

sage: P.reduced_norm('x')
x^3 + x^2 + 2*x + 2
>>> from sage.all import *
>>> P.reduced_norm('x')
x^3 + x^2 + 2*x + 2
coimage(names=None)[source]

Return True if this morphism is injective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2
sage: M = S.quotient_module(P^2, names='m')
sage: M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
sage: N = S.quotient_module(P, names='n')
sage: N.inject_variables()
Defining n0, n1, n2

sage: f = M.hom({m0: n0})
sage: coim = f.coimage()
sage: coim
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: coim.basis()
[m3, m4, m5]
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2)
>>> M = S.quotient_module(P**Integer(2), names='m')
>>> M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
>>> N = S.quotient_module(P, names='n')
>>> N.inject_variables()
Defining n0, n1, n2

>>> f = M.hom({m0: n0})
>>> coim = f.coimage()
>>> coim
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> coim.basis()
[m3, m4, m5]
cokernel(names=None)[source]

Return True if this morphism is injective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2
sage: M = S.quotient_module(P^2, names='m')
sage: M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
sage: N = S.quotient_module(P, names='n')
sage: N.inject_variables()
Defining n0, n1, n2

sage: f = N.hom({n0: P*m0})
sage: coker = f.cokernel()
sage: coker
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: coker.basis()
[m3, m4, m5]
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2)
>>> M = S.quotient_module(P**Integer(2), names='m')
>>> M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
>>> N = S.quotient_module(P, names='n')
>>> N.inject_variables()
Defining n0, n1, n2

>>> f = N.hom({n0: P*m0})
>>> coker = f.cokernel()
>>> coker
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> coker.basis()
[m3, m4, m5]
det()[source]

Return the determinant of this endomorphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M.<m0,m1> = S.quotient_module(X^2 + z)
sage: f = M.multiplication_map(X^3)
sage: f.determinant()
2
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + z, names=('m0', 'm1',)); (m0, m1,) = M._first_ngens(2)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.determinant()
2

If the domain differs from the codomain (even if they have the same rank), an error is raised:

sage: N.<n0,n1> = S.quotient_module(X^2 + z^25)
sage: g = M.hom({z*m0: n0})
sage: g.determinant()
Traceback (most recent call last):
...
ValueError: determinants are only defined for endomorphisms
>>> from sage.all import *
>>> N = S.quotient_module(X**Integer(2) + z**Integer(25), names=('n0', 'n1',)); (n0, n1,) = N._first_ngens(2)
>>> g = M.hom({z*m0: n0})
>>> g.determinant()
Traceback (most recent call last):
...
ValueError: determinants are only defined for endomorphisms
determinant()[source]

Return the determinant of this endomorphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M.<m0,m1> = S.quotient_module(X^2 + z)
sage: f = M.multiplication_map(X^3)
sage: f.determinant()
2
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + z, names=('m0', 'm1',)); (m0, m1,) = M._first_ngens(2)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.determinant()
2

If the domain differs from the codomain (even if they have the same rank), an error is raised:

sage: N.<n0,n1> = S.quotient_module(X^2 + z^25)
sage: g = M.hom({z*m0: n0})
sage: g.determinant()
Traceback (most recent call last):
...
ValueError: determinants are only defined for endomorphisms
>>> from sage.all import *
>>> N = S.quotient_module(X**Integer(2) + z**Integer(25), names=('n0', 'n1',)); (n0, n1,) = N._first_ngens(2)
>>> g = M.hom({z*m0: n0})
>>> g.determinant()
Traceback (most recent call last):
...
ValueError: determinants are only defined for endomorphisms
image(names=None)[source]

Return True if this morphism is injective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2
sage: M = S.quotient_module(P^2, names='m')
sage: M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
sage: N = S.quotient_module(P, names='n')
sage: N.inject_variables()
Defining n0, n1, n2

sage: f = N.hom({n0: P*m0})
sage: im = f.image()
sage: im
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: im.basis()
[m0 + (2*z^2+3*z+1)*m3 + (4*z^2+3*z+3)*m4 + (2*z^2+3*z)*m5,
 m1 + (z+3)*m3 + (z^2+z+4)*m4,
 m2 + (2*z^2+4*z+2)*m4 + (2*z^2+z+1)*m5]
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2)
>>> M = S.quotient_module(P**Integer(2), names='m')
>>> M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
>>> N = S.quotient_module(P, names='n')
>>> N.inject_variables()
Defining n0, n1, n2

>>> f = N.hom({n0: P*m0})
>>> im = f.image()
>>> im
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> im.basis()
[m0 + (2*z^2+3*z+1)*m3 + (4*z^2+3*z+3)*m4 + (2*z^2+3*z)*m5,
 m1 + (z+3)*m3 + (z^2+z+4)*m4,
 m2 + (2*z^2+4*z+2)*m4 + (2*z^2+z+1)*m5]
inverse()[source]

Return the inverse of this morphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^2 + z
sage: M.<e0,e1,e2,e3> = S.quotient_module(P^2)

sage: f = M.multiplication_map(X^3)
sage: g = f.inverse()
sage: (f*g).is_identity()
True
sage: (g*f).is_identity()
True
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(2) + z
>>> M = S.quotient_module(P**Integer(2), names=('e0', 'e1', 'e2', 'e3',)); (e0, e1, e2, e3,) = M._first_ngens(4)

>>> f = M.multiplication_map(X**Integer(3))
>>> g = f.inverse()
>>> (f*g).is_identity()
True
>>> (g*f).is_identity()
True

If the morphism is not invertible, an error is raised:

sage: h = M.hom({e0: P*e0})
sage: h.inverse()
Traceback (most recent call last):
...
ValueError: this morphism is not invertible
>>> from sage.all import *
>>> h = M.hom({e0: P*e0})
>>> h.inverse()
Traceback (most recent call last):
...
ValueError: this morphism is not invertible
is_bijective()[source]

Return True if this morphism is bijective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M = S.quotient_module(X^2 + z)
sage: f = M.multiplication_map(X^3)
sage: f.is_bijective()
True

sage: N = S.quotient_module(X^2)
sage: g = N.multiplication_map(X^3)
sage: g.is_bijective()
False
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + z)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.is_bijective()
True

>>> N = S.quotient_module(X**Integer(2))
>>> g = N.multiplication_map(X**Integer(3))
>>> g.is_bijective()
False
is_identity()[source]

Return True if this morphism is the identity.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M.<v,w> = S.quotient_module(X^2 + z)
sage: f = M.hom({v: v})
sage: f.is_identity()
True

sage: f = M.hom({v: 2*v})
sage: f.is_identity()
False
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + z, names=('v', 'w',)); (v, w,) = M._first_ngens(2)
>>> f = M.hom({v: v})
>>> f.is_identity()
True

>>> f = M.hom({v: Integer(2)*v})
>>> f.is_identity()
False
is_injective()[source]

Return True if this morphism is injective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2
sage: M = S.quotient_module(P^2, names='m')
sage: M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
sage: N = S.quotient_module(P, names='n')
sage: N.inject_variables()
Defining n0, n1, n2

sage: f = N.hom({n0: P*m0})
sage: f.is_injective()
True

sage: g = M.hom({m0: n0})
sage: g.is_injective()
False
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2)
>>> M = S.quotient_module(P**Integer(2), names='m')
>>> M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
>>> N = S.quotient_module(P, names='n')
>>> N.inject_variables()
Defining n0, n1, n2

>>> f = N.hom({n0: P*m0})
>>> f.is_injective()
True

>>> g = M.hom({m0: n0})
>>> g.is_injective()
False
is_isomorphism()[source]

Return True if this morphism is an isomorphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M = S.quotient_module(X^2 + z)
sage: f = M.multiplication_map(X^3)
sage: f.is_isomorphism()
True

sage: N = S.quotient_module(X^2)
sage: g = N.multiplication_map(X^3)
sage: g.is_isomorphism()
False
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + z)
>>> f = M.multiplication_map(X**Integer(3))
>>> f.is_isomorphism()
True

>>> N = S.quotient_module(X**Integer(2))
>>> g = N.multiplication_map(X**Integer(3))
>>> g.is_isomorphism()
False
is_surjective()[source]

Return True if this morphism is surjective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2
sage: M = S.quotient_module(P^2, names='m')
sage: M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
sage: N = S.quotient_module(P, names='n')
sage: N.inject_variables()
Defining n0, n1, n2

sage: f = N.hom({n0: P*m0})
sage: f.is_surjective()
False

sage: g = M.hom({m0: n0})
sage: g.is_surjective()
True
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2)
>>> M = S.quotient_module(P**Integer(2), names='m')
>>> M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
>>> N = S.quotient_module(P, names='n')
>>> N.inject_variables()
Defining n0, n1, n2

>>> f = N.hom({n0: P*m0})
>>> f.is_surjective()
False

>>> g = M.hom({m0: n0})
>>> g.is_surjective()
True
is_zero()[source]

Return True if this morphism is zero.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2 + 1
sage: M = S.quotient_module(P^2, names='e')
sage: M.inject_variables()
Defining e0, e1, e2, e3, e4, e5

sage: f = M.hom({e0: P*e0})
sage: f.is_zero()
False
sage: (f*f).is_zero()
True
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2) + Integer(1)
>>> M = S.quotient_module(P**Integer(2), names='e')
>>> M.inject_variables()
Defining e0, e1, e2, e3, e4, e5

>>> f = M.hom({e0: P*e0})
>>> f.is_zero()
False
>>> (f*f).is_zero()
True
kernel(names=None)[source]

Return True if this morphism is injective.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: P = X^3 + z*X^2 + z^2
sage: M = S.quotient_module(P^2, names='m')
sage: M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
sage: N = S.quotient_module(P, names='n')
sage: N.inject_variables()
Defining n0, n1, n2

sage: f = M.hom({m0: n0})
sage: ker = f.kernel()
sage: ker
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
sage: ker.basis()
[m0 + (2*z^2+3*z+1)*m3 + (4*z^2+3*z+3)*m4 + (2*z^2+3*z)*m5,
 m1 + (z+3)*m3 + (z^2+z+4)*m4,
 m2 + (2*z^2+4*z+2)*m4 + (2*z^2+z+1)*m5]
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> P = X**Integer(3) + z*X**Integer(2) + z**Integer(2)
>>> M = S.quotient_module(P**Integer(2), names='m')
>>> M.inject_variables()
Defining m0, m1, m2, m3, m4, m5
>>> N = S.quotient_module(P, names='n')
>>> N.inject_variables()
Defining n0, n1, n2

>>> f = M.hom({m0: n0})
>>> ker = f.kernel()
>>> ker
Ore module of rank 3 over Finite Field in z of size 5^3 twisted by z |--> z^5
>>> ker.basis()
[m0 + (2*z^2+3*z+1)*m3 + (4*z^2+3*z+3)*m4 + (2*z^2+3*z)*m5,
 m1 + (z+3)*m3 + (z^2+z+4)*m4,
 m2 + (2*z^2+4*z+2)*m4 + (2*z^2+z+1)*m5]
matrix()[source]

Return the matrix defining this morphism.

EXAMPLES:

sage: K.<z> = GF(5^3)
sage: S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
sage: M = S.quotient_module(X^2 + z)
sage: f = M.multiplication_map(2)
sage: f.matrix()
[2 0]
[0 2]

sage: g = M.multiplication_map(X^3)
sage: g.matrix()
[            0 3*z^2 + z + 1]
[      2*z + 1             0]
>>> from sage.all import *
>>> K = GF(Integer(5)**Integer(3), names=('z',)); (z,) = K._first_ngens(1)
>>> S = OrePolynomialRing(K, K.frobenius_endomorphism(), names=('X',)); (X,) = S._first_ngens(1)
>>> M = S.quotient_module(X**Integer(2) + z)
>>> f = M.multiplication_map(Integer(2))
>>> f.matrix()
[2 0]
[0 2]

>>> g = M.multiplication_map(X**Integer(3))
>>> g.matrix()
[            0 3*z^2 + z + 1]
[      2*z + 1             0]
class sage.modules.ore_module_morphism.OreModuleRetraction[source]

Bases: Map

Conversion (partially defined) map from an ambient module to one of its submodule.

class sage.modules.ore_module_morphism.OreModuleSection[source]

Bases: Map

Section map of the projection onto a quotient. It is not necessarily compatible with the Ore action.