Pseudomorphisms of free modules

AUTHORS:

  • Xavier Caruso, Yossef Musleh (2024-09): initial version

class sage.modules.free_module_pseudomorphism.FreeModulePseudoMorphism(parent, f, side)[source]

Bases: Morphism

Let M,M be modules over a ring R, θ:RR a ring homomorphism, and δ:RR a θ-derivation, which is a map such that:

δ(xy)=θ(x)δ(y)+δ(x)y.

A pseudomorphism f:MM is an additive map such that

f(λx)=θ(λ)f(x)+δ(λ)x

The map θ (resp. δ) is referred to as the twisting endomorphism (resp. the twisting derivation) of f.

Note

The implementation currently requires that M and M are free modules.

We represent pseudomorphisms by matrices with coefficient in the base ring R. The matrix Mf representing f is such that its lines (resp. columns if side is "right") are the coordinates of the images of the distinguished basis of the domain (see also method matrix()). More concretely, let n (resp. n) be the dimension of M (resp. M), let (e1,,en) be a basis of M. For any x=i=1nxieiM, we have

f(x)=(θ(x1)θ(xn))Mf+(δ(x1)θ(xn)).

When side is "right", the formula is

f(x)=Mf(θ(x1)θ(xn))+(δ(x1)θ(xn)).

This class is not supposed to be instantiated directly; the user should use instead the method sage.rings.module.free_module.FreeModule_generic.pseudohom() to create a pseudomorphism.

matrix()[source]

Return the underlying matrix of this pseudomorphism.

It is defined as the matrix M whose lines (resp. columns if side is "right") are the coordinates of the images of the distinguished basis of the domain.

EXAMPLES:

sage: Fq.<z> = GF(7^3)
sage: Frob = Fq.frobenius_endomorphism()
sage: M = Fq^3
sage: f = M.pseudohom([[1, z, 3], [0, 1, z^2], [z+1, 1, 1]], Frob)
sage: f.matrix()
[    1     z     3]
[    0     1   z^2]
[z + 1     1     1]
>>> from sage.all import *
>>> Fq = GF(Integer(7)**Integer(3), names=('z',)); (z,) = Fq._first_ngens(1)
>>> Frob = Fq.frobenius_endomorphism()
>>> M = Fq**Integer(3)
>>> f = M.pseudohom([[Integer(1), z, Integer(3)], [Integer(0), Integer(1), z**Integer(2)], [z+Integer(1), Integer(1), Integer(1)]], Frob)
>>> f.matrix()
[    1     z     3]
[    0     1   z^2]
[z + 1     1     1]
Fq.<z> = GF(7^3)
Frob = Fq.frobenius_endomorphism()
M = Fq^3
f = M.pseudohom([[1, z, 3], [0, 1, z^2], [z+1, 1, 1]], Frob)
f.matrix()

sage: e1, e2, e3 = M.basis()
sage: f(e1)
(1, z, 3)
sage: f(e2)
(0, 1, z^2)
sage: f(e3)
(z + 1, 1, 1)
>>> from sage.all import *
>>> e1, e2, e3 = M.basis()
>>> f(e1)
(1, z, 3)
>>> f(e2)
(0, 1, z^2)
>>> f(e3)
(z + 1, 1, 1)
e1, e2, e3 = M.basis()
f(e1)
f(e2)
f(e3)
ore_module(names=None)[source]

Return the Ore module over which the Ore variable acts through this pseudomorphism.

INPUT:

  • names – a string, a list of strings or None, the names of the vector of the canonical basis of the Ore module; if None, elements are represented as vectors in Kd (where K is the base ring)

EXAMPLES:

sage: Fq.<z> = GF(7^3)
sage: Frob = Fq.frobenius_endomorphism()
sage: V = Fq^2
sage: mat = matrix(2, [1, z, z^2, z^3])
sage: f = V.pseudohom(mat, Frob)

sage: M = f.ore_module()
sage: M
Ore module of rank 2 over Finite Field in z of size 7^3 twisted by z |--> z^7
>>> from sage.all import *
>>> Fq = GF(Integer(7)**Integer(3), names=('z',)); (z,) = Fq._first_ngens(1)
>>> Frob = Fq.frobenius_endomorphism()
>>> V = Fq**Integer(2)
>>> mat = matrix(Integer(2), [Integer(1), z, z**Integer(2), z**Integer(3)])
>>> f = V.pseudohom(mat, Frob)

>>> M = f.ore_module()
>>> M
Ore module of rank 2 over Finite Field in z of size 7^3 twisted by z |--> z^7
Fq.<z> = GF(7^3)
Frob = Fq.frobenius_endomorphism()
V = Fq^2
mat = matrix(2, [1, z, z^2, z^3])
f = V.pseudohom(mat, Frob)
M = f.ore_module()
M

Here M is a module over the Ore ring Fq[X;Frob] and the variable X acts on M through f:

sage: S.<X> = M.ore_ring()
sage: S
Ore Polynomial Ring in X over Finite Field in z of size 7^3 twisted by z |--> z^7
sage: v = M((1,0))
sage: X*v
(1, z)
>>> from sage.all import *
>>> S = M.ore_ring(names=('X',)); (X,) = S._first_ngens(1)
>>> S
Ore Polynomial Ring in X over Finite Field in z of size 7^3 twisted by z |--> z^7
>>> v = M((Integer(1),Integer(0)))
>>> X*v
(1, z)
S.<X> = M.ore_ring()
S
v = M((1,0))
X*v

The argument names can be used to give chosen names to the vectors in the canonical basis:

sage: M = f.ore_module(names=('v', 'w'))
sage: M.basis()
[v, w]
>>> from sage.all import *
>>> M = f.ore_module(names=('v', 'w'))
>>> M.basis()
[v, w]
M = f.ore_module(names=('v', 'w'))
M.basis()

or even:

sage: M = f.ore_module(names='e')
sage: M.basis()
[e0, e1]
>>> from sage.all import *
>>> M = f.ore_module(names='e')
>>> M.basis()
[e0, e1]
M = f.ore_module(names='e')
M.basis()

Note that the bracket construction also works:

sage: M.<v,w> = f.ore_module()
sage: M.basis()
[v, w]
sage: v + w
v + w
>>> from sage.all import *
>>> M = f.ore_module(names=('v', 'w',)); (v, w,) = M._first_ngens(2)
>>> M.basis()
[v, w]
>>> v + w
v + w
M.<v,w> = f.ore_module()
M.basis()
v + w

We refer to sage.modules.ore_module for a tutorial on Ore modules in SageMath.

side()[source]

Return the side of vectors acted on, relative to the matrix.

EXAMPLES:

sage: Fq.<z> = GF(7^3)
sage: Frob = Fq.frobenius_endomorphism()
sage: V = Fq^2

sage: m = matrix(2, [1, z, z^2, z^3])
sage: h1 = V.pseudohom(m, Frob)
sage: h1.side()
'left'
sage: h1([1, 0])
(1, z)

sage: h2 = V.pseudohom(m, Frob, side="right")
sage: h2.side()
'right'
sage: h2([1, 0])
(1, z^2)
>>> from sage.all import *
>>> Fq = GF(Integer(7)**Integer(3), names=('z',)); (z,) = Fq._first_ngens(1)
>>> Frob = Fq.frobenius_endomorphism()
>>> V = Fq**Integer(2)

>>> m = matrix(Integer(2), [Integer(1), z, z**Integer(2), z**Integer(3)])
>>> h1 = V.pseudohom(m, Frob)
>>> h1.side()
'left'
>>> h1([Integer(1), Integer(0)])
(1, z)

>>> h2 = V.pseudohom(m, Frob, side="right")
>>> h2.side()
'right'
>>> h2([Integer(1), Integer(0)])
(1, z^2)
Fq.<z> = GF(7^3)
Frob = Fq.frobenius_endomorphism()
V = Fq^2
m = matrix(2, [1, z, z^2, z^3])
h1 = V.pseudohom(m, Frob)
h1.side()
h1([1, 0])
h2 = V.pseudohom(m, Frob, side="right")
h2.side()
h2([1, 0])
side_switch()[source]

Return the same morphism, acting on vectors on the opposite side.

EXAMPLES:

sage: Fq.<z> = GF(7^3)
sage: Frob = Fq.frobenius_endomorphism()
sage: V = Fq^2

sage: m = matrix(2, [1, z, z^2, z^3])
sage: h1 = V.pseudohom(m, Frob)
sage: h1
Free module pseudomorphism (twisted by z |--> z^7) defined by the matrix
[      1       z]
[    z^2 z^2 + 3]
Domain: Vector space of dimension 2 over Finite Field in z of size 7^3
Codomain: Vector space of dimension 2 over Finite Field in z of size 7^3

sage: h2 = h1.side_switch()
sage: h2
Free module pseudomorphism (twisted by z |--> z^7) defined as left-multiplication by the matrix
[      1     z^2]
[      z z^2 + 3]
Domain: Vector space of dimension 2 over Finite Field in z of size 7^3
Codomain: Vector space of dimension 2 over Finite Field in z of size 7^3
>>> from sage.all import *
>>> Fq = GF(Integer(7)**Integer(3), names=('z',)); (z,) = Fq._first_ngens(1)
>>> Frob = Fq.frobenius_endomorphism()
>>> V = Fq**Integer(2)

>>> m = matrix(Integer(2), [Integer(1), z, z**Integer(2), z**Integer(3)])
>>> h1 = V.pseudohom(m, Frob)
>>> h1
Free module pseudomorphism (twisted by z |--> z^7) defined by the matrix
[      1       z]
[    z^2 z^2 + 3]
Domain: Vector space of dimension 2 over Finite Field in z of size 7^3
Codomain: Vector space of dimension 2 over Finite Field in z of size 7^3

>>> h2 = h1.side_switch()
>>> h2
Free module pseudomorphism (twisted by z |--> z^7) defined as left-multiplication by the matrix
[      1     z^2]
[      z z^2 + 3]
Domain: Vector space of dimension 2 over Finite Field in z of size 7^3
Codomain: Vector space of dimension 2 over Finite Field in z of size 7^3
Fq.<z> = GF(7^3)
Frob = Fq.frobenius_endomorphism()
V = Fq^2
m = matrix(2, [1, z, z^2, z^3])
h1 = V.pseudohom(m, Frob)
h1
h2 = h1.side_switch()
h2

We check that h1 and h2 are the same:

sage: v = V.random_element()
sage: h1(v) == h2(v)
True
>>> from sage.all import *
>>> v = V.random_element()
>>> h1(v) == h2(v)
True
v = V.random_element()
h1(v) == h2(v)
twisting_derivation()[source]

Return the twisting derivation of the pseudomorphism (or None if the twisting derivation is zero).

EXAMPLES:

sage: P.<x> = ZZ[]
sage: d = P.derivation()
sage: M = P^2
sage: f = M.pseudohom([[1, 2*x], [x, 1]], d)
sage: f.twisting_derivation()
d/dx
>>> from sage.all import *
>>> P = ZZ['x']; (x,) = P._first_ngens(1)
>>> d = P.derivation()
>>> M = P**Integer(2)
>>> f = M.pseudohom([[Integer(1), Integer(2)*x], [x, Integer(1)]], d)
>>> f.twisting_derivation()
d/dx
P.<x> = ZZ[]
d = P.derivation()
M = P^2
f = M.pseudohom([[1, 2*x], [x, 1]], d)
f.twisting_derivation()

sage: Fq.<z> = GF(7^3)
sage: Frob = Fq.frobenius_endomorphism()
sage: V = Fq^2
sage: f = V.pseudohom([[1, z], [0, z^2]], Frob)
sage: f.twisting_derivation()
>>> from sage.all import *
>>> Fq = GF(Integer(7)**Integer(3), names=('z',)); (z,) = Fq._first_ngens(1)
>>> Frob = Fq.frobenius_endomorphism()
>>> V = Fq**Integer(2)
>>> f = V.pseudohom([[Integer(1), z], [Integer(0), z**Integer(2)]], Frob)
>>> f.twisting_derivation()
Fq.<z> = GF(7^3)
Frob = Fq.frobenius_endomorphism()
V = Fq^2
f = V.pseudohom([[1, z], [0, z^2]], Frob)
f.twisting_derivation()
twisting_morphism()[source]

Return the twisting morphism of the pseudomorphism (or None if the twisting morphism is the identity).

EXAMPLES:

sage: Fq.<z> = GF(7^3)
sage: Frob = Fq.frobenius_endomorphism()
sage: V = Fq^2
sage: f = V.pseudohom([[1, z], [0, z^2]], Frob)
sage: f.twisting_morphism()
Frobenius endomorphism z |--> z^7 on Finite Field in z of size 7^3
>>> from sage.all import *
>>> Fq = GF(Integer(7)**Integer(3), names=('z',)); (z,) = Fq._first_ngens(1)
>>> Frob = Fq.frobenius_endomorphism()
>>> V = Fq**Integer(2)
>>> f = V.pseudohom([[Integer(1), z], [Integer(0), z**Integer(2)]], Frob)
>>> f.twisting_morphism()
Frobenius endomorphism z |--> z^7 on Finite Field in z of size 7^3
Fq.<z> = GF(7^3)
Frob = Fq.frobenius_endomorphism()
V = Fq^2
f = V.pseudohom([[1, z], [0, z^2]], Frob)
f.twisting_morphism()

sage: P.<x> = ZZ[]
sage: d = P.derivation()
sage: M = P^2
sage: f = M.pseudohom([[1, 2*x], [x, 1]], d)
sage: f.twisting_morphism()
>>> from sage.all import *
>>> P = ZZ['x']; (x,) = P._first_ngens(1)
>>> d = P.derivation()
>>> M = P**Integer(2)
>>> f = M.pseudohom([[Integer(1), Integer(2)*x], [x, Integer(1)]], d)
>>> f.twisting_morphism()
P.<x> = ZZ[]
d = P.derivation()
M = P^2
f = M.pseudohom([[1, 2*x], [x, 1]], d)
f.twisting_morphism()