Morphisms between Ore modules

Let R be a commutative ring, θ:RR by a ring endomorphism and :RR be a θ-derivation. Let also S=R[X;θ,] denote the associated Ore polynomial ring.

By definition, a Ore module is a module over 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 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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M.<e0,e1> = S.quotient_module(X^2 + X + z)
mat = matrix(2, 2, [z,     3*z^2 + z + 2,
                    z + 1,       4*z + 4])
f = M.hom(mat)
f

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 S-linearity. Actually here, f was just the multiplication by X3 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
g = M.hom({e0: X^3*e0})
g

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]
g.matrix()

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
h = M.multiplication_map(X^3)
h
g == h

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]
h = M.multiplication_map(2)
h
h.matrix()

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
M.multiplication_map(z)

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

0S/SPS/SPQS/SQ0

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
P = X^2 + z*X + 1
Q = X^3 + z^2*X^2 + X + z
U = S.quotient_module(P, names='u')
U.inject_variables()
V = S.quotient_module(P*Q, names='v')
V.inject_variables()
W = S.quotient_module(Q, names='w')
W.inject_variables()

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})
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
f.kernel()

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
f.kernel().is_zero()

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
f.is_injective()

Similarly, one checks that g is surjective:

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

or equivalently:

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

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
ker = g.kernel()
im = f.image()
ker == im

As a sanity check, one can also verity that the composite gf 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
h = g * f
h
h.is_zero()

Let us now consider another morphism f and build the canonical isomorphism coim fim 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
A = X + z
B = X + z + 1
P = X^2 + X + z
U = S.quotient_module(B*P, names='u')
U.inject_variables()
V = S.quotient_module(P*A, names='v')
V.inject_variables()
f = U.hom({u0: A*v0})
f

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
I = f.image(names='im')
I
C = f.coimage(names='co')
C

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
g = I.morphism_corestriction(f)
g

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
h = C.morphism_quotient(g)
h

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
h.is_isomorphism()

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
H = Hom(C, I)  # the hom space
h2 = H(f)
h2
h == h2

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 X3 on the quotient S/SP 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
P = X^5 + z*X^4 + z^2*X^2 + z + 1
M = S.quotient_module(P)
f = M.multiplication_map(X^3)
f.charpoly()
P.reduced_norm('x')

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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + (z^2 + 3)*X + z^5
M = S.quotient_module(P)
f = M.multiplication_map(X^3)
f.characteristic_polynomial()

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
P.reduced_norm('x')
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + (z^2 + 3)*X + z^5
M = S.quotient_module(P)
f = M.multiplication_map(X^3)
f.characteristic_polynomial()

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
P.reduced_norm('x')
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]
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2
M = S.quotient_module(P^2, names='m')
M.inject_variables()
N = S.quotient_module(P, names='n')
N.inject_variables()
f = M.hom({m0: n0})
coim = f.coimage()
coim
coim.basis()
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]
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2
M = S.quotient_module(P^2, names='m')
M.inject_variables()
N = S.quotient_module(P, names='n')
N.inject_variables()
f = N.hom({n0: P*m0})
coker = f.cokernel()
coker
coker.basis()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M.<m0,m1> = S.quotient_module(X^2 + z)
f = M.multiplication_map(X^3)
f.determinant()

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
N.<n0,n1> = S.quotient_module(X^2 + z^25)
g = M.hom({z*m0: n0})
g.determinant()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M.<m0,m1> = S.quotient_module(X^2 + z)
f = M.multiplication_map(X^3)
f.determinant()

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
N.<n0,n1> = S.quotient_module(X^2 + z^25)
g = M.hom({z*m0: n0})
g.determinant()
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]
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2
M = S.quotient_module(P^2, names='m')
M.inject_variables()
N = S.quotient_module(P, names='n')
N.inject_variables()
f = N.hom({n0: P*m0})
im = f.image()
im
im.basis()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^2 + z
M.<e0,e1,e2,e3> = S.quotient_module(P^2)
f = M.multiplication_map(X^3)
g = f.inverse()
(f*g).is_identity()
(g*f).is_identity()

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
h = M.hom({e0: P*e0})
h.inverse()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M = S.quotient_module(X^2 + z)
f = M.multiplication_map(X^3)
f.is_bijective()
N = S.quotient_module(X^2)
g = N.multiplication_map(X^3)
g.is_bijective()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M.<v,w> = S.quotient_module(X^2 + z)
f = M.hom({v: v})
f.is_identity()
f = M.hom({v: 2*v})
f.is_identity()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2
M = S.quotient_module(P^2, names='m')
M.inject_variables()
N = S.quotient_module(P, names='n')
N.inject_variables()
f = N.hom({n0: P*m0})
f.is_injective()
g = M.hom({m0: n0})
g.is_injective()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M = S.quotient_module(X^2 + z)
f = M.multiplication_map(X^3)
f.is_isomorphism()
N = S.quotient_module(X^2)
g = N.multiplication_map(X^3)
g.is_isomorphism()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2
M = S.quotient_module(P^2, names='m')
M.inject_variables()
N = S.quotient_module(P, names='n')
N.inject_variables()
f = N.hom({n0: P*m0})
f.is_surjective()
g = M.hom({m0: n0})
g.is_surjective()
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
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2 + 1
M = S.quotient_module(P^2, names='e')
M.inject_variables()
f = M.hom({e0: P*e0})
f.is_zero()
(f*f).is_zero()
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]
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
P = X^3 + z*X^2 + z^2
M = S.quotient_module(P^2, names='m')
M.inject_variables()
N = S.quotient_module(P, names='n')
N.inject_variables()
f = M.hom({m0: n0})
ker = f.kernel()
ker
ker.basis()
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]
K.<z> = GF(5^3)
S.<X> = OrePolynomialRing(K, K.frobenius_endomorphism())
M = S.quotient_module(X^2 + z)
f = M.multiplication_map(2)
f.matrix()
g = M.multiplication_map(X^3)
g.matrix()
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.