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 - sideis- "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 \((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 - sideis- "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 - sideis- "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 or- None, the names of the vector of the canonical basis of the Ore module; if- None, 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 - namescan 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_modulefor 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 - h1and- h2are 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 - Noneif 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 - Noneif 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()