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\), \(\theta: R \to R\) a ring homomorphism, and \(\delta: R \to R\) a \(\theta\)-derivation, which is a map such that:
\[\delta(xy) = \theta(x)\delta(y) + \delta(x)y.\]A pseudomorphism \(f : M \to M\) is an additive map such that
\[f(\lambda x) = \theta(\lambda)f(x) + \delta(\lambda) x\]The map \(\theta\) (resp. \(\delta\)) 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 \(\mathcal M_f\) 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 methodmatrix()
). More concretely, let \(n\) (resp. \(n'\)) be the dimension of \(M\) (resp. \(M'\)), let \((e_1, \dots, e_n)\) be a basis of \(M\). For any \(x = \sum_{i=1}^n x_i e_i \in M\), we have\[f(x) = \begin{pmatrix} \theta(x_1) & \cdots & \theta(x_n) \end{pmatrix} \mathcal M_f + \begin{pmatrix} \delta(x_1) & \cdots & \theta(x_n) \end{pmatrix} .\]When
side
is"right"
, the formula is\[\begin{split}f(x) = \mathcal M_f \begin{pmatrix} \theta(x_1) \\ \vdots \\ \theta(x_n) \end{pmatrix} + \begin{pmatrix} \delta(x_1) \\ \vdots \\ \theta(x_n) \end{pmatrix} .\end{split}\]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]
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)
- 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 orNone
, the names of the vector of the canonical basis of the Ore module; ifNone
, elements are represented as vectors in \(K^d\) (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
Here \(M\) is a module over the Ore ring \(\mathbb F_q[X; \text{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)
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]
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]
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
We refer to
sage.modules.ore_module
for a tutorial on Ore modules in SageMath.See also
- 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)
- 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
We check that
h1
andh2
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
- 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
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()
- 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
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()