Free module automorphisms#
Given a free module \(M\) of finite rank over a commutative ring \(R\), an automorphism of \(M\) is a map
that is linear (i.e. is a module homomorphism) and bijective.
Automorphisms of a free module of finite rank are implemented via the class
FreeModuleAutomorphism
.
AUTHORS:
Eric Gourgoulhon (2015): initial version
Michael Jung (2019): improve treatment of the identity element
REFERENCES:
Chaps. 15, 24 of R. Godement: Algebra [God1968]
- class sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism(fmodule, name=None, latex_name=None)#
Bases:
sage.tensor.modules.free_module_tensor.FreeModuleTensor
,sage.structure.element.MultiplicativeGroupElement
Automorphism of a free module of finite rank over a commutative ring.
This is a Sage element class, the corresponding parent class being
FreeModuleLinearGroup
.This class inherits from the classes
FreeModuleTensor
andMultiplicativeGroupElement
.INPUT:
fmodule
– free module \(M\) of finite rank over a commutative ring \(R\), as an instance ofFiniteRankFreeModule
name
– (default:None
) name given to the automorphismlatex_name
– (default:None
) LaTeX symbol to denote the automorphism; if none is provided, the LaTeX symbol is set toname
is_identity
– (default:False
) determines whether the constructed object is the identity automorphism, i.e. the identity map of \(M\) considered as an automorphism (the identity element of the general linear group)
EXAMPLES:
Automorphism of a rank-2 free module over \(\ZZ\):
sage: M = FiniteRankFreeModule(ZZ, 2, name='M', start_index=1) sage: a = M.automorphism(name='a', latex_name=r'\alpha') ; a Automorphism a of the Rank-2 free module M over the Integer Ring sage: a.parent() General linear group of the Rank-2 free module M over the Integer Ring sage: a.parent() is M.general_linear_group() True sage: latex(a) \alpha
Setting the components of
a
w.r.t. a basis of moduleM
:sage: e = M.basis('e') ; e Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring sage: a[:] = [[1,2],[1,3]] sage: a.matrix(e) [1 2] [1 3] sage: a(e[1]).display() a(e_1) = e_1 + e_2 sage: a(e[2]).display() a(e_2) = 2 e_1 + 3 e_2
Actually, the components w.r.t. a given basis can be specified at the construction of the object:
sage: a = M.automorphism(matrix=[[1,2],[1,3]], basis=e, name='a', ....: latex_name=r'\alpha') ; a Automorphism a of the Rank-2 free module M over the Integer Ring sage: a.matrix(e) [1 2] [1 3]
Since e is the module’s default basis, it can be omitted in the argument list:
sage: a == M.automorphism(matrix=[[1,2],[1,3]], name='a', ....: latex_name=r'\alpha') True
The matrix of the automorphism can be obtained in any basis:
sage: f = M.basis('f', from_family=(3*e[1]+4*e[2], 5*e[1]+7*e[2])) ; f Basis (f_1,f_2) on the Rank-2 free module M over the Integer Ring sage: a.matrix(f) [2 3] [1 2]
Automorphisms are tensors of type \((1,1)\):
sage: a.tensor_type() (1, 1) sage: a.tensor_rank() 2
In particular, they can be displayed as such:
sage: a.display(e) a = e_1⊗e^1 + 2 e_1⊗e^2 + e_2⊗e^1 + 3 e_2⊗e^2 sage: a.display(f) a = 2 f_1⊗f^1 + 3 f_1⊗f^2 + f_2⊗f^1 + 2 f_2⊗f^2
The automorphism acting on a module element:
sage: v = M([-2,3], name='v') ; v Element v of the Rank-2 free module M over the Integer Ring sage: a(v) Element a(v) of the Rank-2 free module M over the Integer Ring sage: a(v).display() a(v) = 4 e_1 + 7 e_2
A second automorphism of the module
M
:sage: b = M.automorphism([[0,1],[-1,0]], name='b') ; b Automorphism b of the Rank-2 free module M over the Integer Ring sage: b.matrix(e) [ 0 1] [-1 0] sage: b(e[1]).display() b(e_1) = -e_2 sage: b(e[2]).display() b(e_2) = e_1
The composition of automorphisms is performed via the multiplication operator:
sage: s = a*b ; s Automorphism of the Rank-2 free module M over the Integer Ring sage: s(v) == a(b(v)) True sage: s.matrix(f) [ 11 19] [ -7 -12] sage: s.matrix(f) == a.matrix(f) * b.matrix(f) True
It is not commutative:
sage: a*b != b*a True
In other words, the parent of
a
andb
, i.e. the group \(\mathrm{GL}(M)\), is not abelian:sage: M.general_linear_group() in CommutativeAdditiveGroups() False
The neutral element for the composition law is the module identity map:
sage: id = M.identity_map() ; id Identity map of the Rank-2 free module M over the Integer Ring sage: id.parent() General linear group of the Rank-2 free module M over the Integer Ring sage: id(v) == v True sage: id.matrix(f) [1 0] [0 1] sage: id*a == a True sage: a*id == a True
The inverse of an automorphism is obtained via the method
inverse()
, or the operator ~, or the exponent -1:sage: a.inverse() Automorphism a^(-1) of the Rank-2 free module M over the Integer Ring sage: a.inverse() is ~a True sage: a.inverse() is a^(-1) True sage: (a^(-1)).matrix(e) [ 3 -2] [-1 1] sage: a*a^(-1) == id True sage: a^(-1)*a == id True sage: a^(-1)*s == b True sage: (a^(-1))(a(v)) == v True
The module’s changes of basis are stored as automorphisms:
sage: M.change_of_basis(e,f) Automorphism of the Rank-2 free module M over the Integer Ring sage: M.change_of_basis(e,f).parent() General linear group of the Rank-2 free module M over the Integer Ring sage: M.change_of_basis(e,f).matrix(e) [3 5] [4 7] sage: M.change_of_basis(f,e) == M.change_of_basis(e,f).inverse() True
The opposite of an automorphism is still an automorphism:
sage: -a Automorphism -a of the Rank-2 free module M over the Integer Ring sage: (-a).parent() General linear group of the Rank-2 free module M over the Integer Ring sage: (-a).matrix(e) == - (a.matrix(e)) True
Adding two automorphisms results in a generic type-\((1,1)\) tensor:
sage: s = a + b ; s Type-(1,1) tensor a+b on the Rank-2 free module M over the Integer Ring sage: s.parent() Free module of type-(1,1) tensors on the Rank-2 free module M over the Integer Ring sage: a[:], b[:], s[:] ( [1 2] [ 0 1] [1 3] [1 3], [-1 0], [0 3] )
To get the result as an endomorphism, one has to explicitly convert it via the parent of endomorphisms, \(\mathrm{End}(M)\):
sage: s = End(M)(a+b) ; s Generic endomorphism of Rank-2 free module M over the Integer Ring sage: s(v) == a(v) + b(v) True sage: s.matrix(e) == a.matrix(e) + b.matrix(e) True sage: s.matrix(f) == a.matrix(f) + b.matrix(f) True
- add_comp(basis=None)#
Return the components of
self
w.r.t. a given module basis for assignment, keeping the components w.r.t. other bases.To delete the components w.r.t. other bases, use the method
set_comp()
instead.INPUT:
basis
– (default:None
) basis in which the components are defined; if none is provided, the components are assumed to refer to the module’s default basis
Warning
If the automorphism has already components in other bases, it is the user’s responsibility to make sure that the components to be added are consistent with them.
OUTPUT:
components in the given basis, as an instance of the class
Components
; if such components did not exist previously, they are created
EXAMPLES:
Adding components to an automorphism of a rank-3 free \(\ZZ\)-module:
sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism(name='a') sage: a[e,:] = [[1,0,0],[0,-1,2],[0,1,-3]] sage: f = M.basis('f', from_family=(-e[0], 3*e[1]+4*e[2], ....: 5*e[1]+7*e[2])) ; f Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring sage: a.add_comp(f)[:] = [[1,0,0], [0, 80, 143], [0, -47, -84]]
The components in basis
e
have been kept:sage: a._components # random (dictionary output) {Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring, Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring}
For the identity map, it is not permitted to invoke
add_comp()
:sage: id = M.identity_map() sage: id.add_comp(e) Traceback (most recent call last): ... ValueError: the components of the identity map cannot be changed
Indeed, the components are set automatically:
sage: id.comp(e) Kronecker delta of size 3x3 sage: id.comp(f) Kronecker delta of size 3x3
- det()#
Return the determinant of
self
.OUTPUT:
element of the base ring of the module on which
self
is defined, equal to the determinant ofself
.
EXAMPLES:
Determinant of an automorphism on a \(\ZZ\)-module of rank 2:
sage: M = FiniteRankFreeModule(ZZ, 2, name='M') sage: e = M.basis('e') sage: a = M.automorphism([[4,7],[3,5]], name='a') sage: a.matrix(e) [4 7] [3 5] sage: a.det() -1 sage: det(a) -1 sage: ~a.det() # determinant of the inverse automorphism -1 sage: id = M.identity_map() sage: id.det() 1
- inverse()#
Return the inverse automorphism.
OUTPUT:
instance of
FreeModuleAutomorphism
representing the automorphism that is the inverse ofself
.
EXAMPLES:
Inverse of an automorphism of a rank-3 free module:
sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism(name='a') sage: a[e,:] = [[1,0,0],[0,-1,2],[0,1,-3]] sage: a.inverse() Automorphism a^(-1) of the Rank-3 free module M over the Integer Ring sage: a.inverse().parent() General linear group of the Rank-3 free module M over the Integer Ring
Check that
a.inverse()
is indeed the inverse automorphism:sage: a.inverse() * a Identity map of the Rank-3 free module M over the Integer Ring sage: a * a.inverse() Identity map of the Rank-3 free module M over the Integer Ring sage: a.inverse().inverse() == a True
Another check is:
sage: a.inverse().matrix(e) [ 1 0 0] [ 0 -3 -2] [ 0 -1 -1] sage: a.inverse().matrix(e) == (a.matrix(e))^(-1) True
The inverse is cached (as long as
a
is not modified):sage: a.inverse() is a.inverse() True
If
a
is modified, the inverse is automatically recomputed:sage: a[0,0] = -1 sage: a.matrix(e) [-1 0 0] [ 0 -1 2] [ 0 1 -3] sage: a.inverse().matrix(e) # compare with above [-1 0 0] [ 0 -3 -2] [ 0 -1 -1]
Shortcuts for
inverse()
are the operator~
and the exponent-1
:sage: ~a is a.inverse() True sage: (a)^(-1) is a.inverse() True
The inverse of the identity map is of course itself:
sage: id = M.identity_map() sage: id.inverse() is id True
and we have:
sage: a*(a)^(-1) == id True sage: (a)^(-1)*a == id True
If the name could cause some confusion, a bracket is added around the element before taking the inverse:
sage: c = M.automorphism(name='a^(-1)*b') sage: c[e,:] = [[1,0,0],[0,-1,1],[0,2,-1]] sage: c.inverse() Automorphism (a^(-1)*b)^(-1) of the Rank-3 free module M over the Integer Ring
- matrix(basis1=None, basis2=None)#
Return the matrix of
self
w.r.t to a pair of bases.If the matrix is not known already, it is computed from the matrix in another pair of bases by means of the change-of-basis formula.
INPUT:
basis1
– (default:None
) basis of the free module on whichself
is defined; if none is provided, the module’s default basis is assumedbasis2
– (default:None
) basis of the free module on whichself
is defined; if none is provided,basis2
is set tobasis1
OUTPUT:
the matrix representing the automorphism
self
w.r.t to basesbasis1
andbasis2
; more precisely, the columns of this matrix are formed by the components w.r.t.basis2
of the images of the elements ofbasis1
.
EXAMPLES:
Matrices of an automorphism of a rank-3 free \(\ZZ\)-module:
sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1) sage: e = M.basis('e') sage: a = M.automorphism([[-1,0,0],[0,1,2],[0,1,3]], name='a') sage: a.matrix(e) [-1 0 0] [ 0 1 2] [ 0 1 3] sage: a.matrix() [-1 0 0] [ 0 1 2] [ 0 1 3] sage: f = M.basis('f', from_family=(-e[2], 4*e[1]+3*e[3], 7*e[1]+5*e[3])) ; f Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring sage: a.matrix(f) [ 1 -6 -10] [ -7 83 140] [ 4 -48 -81]
Check of the above matrix:
sage: a(f[1]).display(f) a(f_1) = f_1 - 7 f_2 + 4 f_3 sage: a(f[2]).display(f) a(f_2) = -6 f_1 + 83 f_2 - 48 f_3 sage: a(f[3]).display(f) a(f_3) = -10 f_1 + 140 f_2 - 81 f_3
Check of the change-of-basis formula:
sage: P = M.change_of_basis(e,f).matrix(e) sage: a.matrix(f) == P^(-1) * a.matrix(e) * P True
Check that the matrix of the product of two automorphisms is the product of their matrices:
sage: b = M.change_of_basis(e,f) ; b Automorphism of the Rank-3 free module M over the Integer Ring sage: b.matrix(e) [ 0 4 7] [-1 0 0] [ 0 3 5] sage: (a*b).matrix(e) == a.matrix(e) * b.matrix(e) True
Check that the matrix of the inverse automorphism is the inverse of the automorphism’s matrix:
sage: (~a).matrix(e) [-1 0 0] [ 0 3 -2] [ 0 -1 1] sage: (~a).matrix(e) == ~(a.matrix(e)) True
Matrices of the identity map:
sage: id = M.identity_map() sage: id.matrix(e) [1 0 0] [0 1 0] [0 0 1] sage: id.matrix(f) [1 0 0] [0 1 0] [0 0 1]
- set_comp(basis=None)#
Return the components of
self
w.r.t. a given module basis for assignment.The components with respect to other bases are deleted, in order to avoid any inconsistency. To keep them, use the method
add_comp()
instead.INPUT:
basis
– (default:None
) basis in which the components are defined; if none is provided, the components are assumed to refer to the module’s default basis
OUTPUT:
components in the given basis, as an instance of the class
Components
; if such components did not exist previously, they are created.
EXAMPLES:
Setting the components of an automorphism of a rank-3 free \(\ZZ\)-module:
sage: M = FiniteRankFreeModule(ZZ, 3, name='M') sage: e = M.basis('e') sage: a = M.automorphism(name='a') sage: a.set_comp(e) 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring sage: a.set_comp(e)[:] = [[1,0,0],[0,1,2],[0,1,3]] sage: a.matrix(e) [1 0 0] [0 1 2] [0 1 3]
Since
e
is the module’s default basis, one has:sage: a.set_comp() is a.set_comp(e) True
The method
set_comp()
can be used to modify a single component:sage: a.set_comp(e)[0,0] = -1 sage: a.matrix(e) [-1 0 0] [ 0 1 2] [ 0 1 3]
A short cut to
set_comp()
is the bracket operator, with the basis as first argument:sage: a[e,:] = [[1,0,0],[0,-1,2],[0,1,-3]] sage: a.matrix(e) [ 1 0 0] [ 0 -1 2] [ 0 1 -3] sage: a[e,0,0] = -1 sage: a.matrix(e) [-1 0 0] [ 0 -1 2] [ 0 1 -3]
The call to
set_comp()
erases the components previously defined in other bases; to keep them, use the methodadd_comp()
instead:sage: f = M.basis('f', from_family=(-e[0], 3*e[1]+4*e[2], ....: 5*e[1]+7*e[2])) ; f Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring sage: a._components {Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring} sage: a.set_comp(f)[:] = [[-1,0,0], [0,1,0], [0,0,-1]]
The components w.r.t. basis
e
have been erased:sage: a._components {Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring: 2-indices components w.r.t. Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring}
Of course, they can be computed from those in basis
f
by means of a change-of-basis formula, via the methodcomp()
ormatrix()
:sage: a.matrix(e) [ -1 0 0] [ 0 41 -30] [ 0 56 -41]
For the identity map, it is not permitted to set components:
sage: id = M.identity_map() sage: id.set_comp(e) Traceback (most recent call last): ... ValueError: the components of the identity map cannot be changed
Indeed, the components are set automatically:
sage: id.comp(e) Kronecker delta of size 3x3 sage: id.comp(f) Kronecker delta of size 3x3
- trace()#
Return the trace of
self
.OUTPUT:
element of the base ring of the module on which
self
is defined, equal to the trace ofself
.
EXAMPLES:
Trace of an automorphism on a \(\ZZ\)-module of rank 2:
sage: M = FiniteRankFreeModule(ZZ, 2, name='M') sage: e = M.basis('e') sage: a = M.automorphism([[4,7],[3,5]], name='a') sage: a.matrix(e) [4 7] [3 5] sage: a.trace() 9 sage: id = M.identity_map() sage: id.trace() 2