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
REFERENCES:
- Chaps. 15, 24 of R. Godement: Algebra, Hermann (Paris) / Houghton Mifflin (Boston) (1968)
-
class
sage.tensor.modules.free_module_automorphism.
FreeModuleAutomorphism
(fmodule, name=None, latex_name=None, is_identity=False)¶ 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 explicitely convert it via the parent of endormophisms, \(\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 responsability 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
EXAMPLE:
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): ... TypeError: the components of the identity map cannot be changed
Indeed, the components are automatically set by a call to
comp()
:sage: id.comp(e) Kronecker delta of size 3x3 sage: id.comp(f) Kronecker delta of size 3x3
-
comp
(basis=None, from_basis=None)¶ Return the components of
self
w.r.t to a given module basis.If the components are not known already, they are computed by the tensor change-of-basis formula from components in another basis.
INPUT:
basis
– (default:None
) basis in which the components are required; if none is provided, the components are assumed to refer to the module’s default basisfrom_basis
– (default:None
) basis from which the required components are computed, via the tensor change-of-basis formula, if they are not known already in the basisbasis
; if none, a basis from which both the components and a change-of-basis tobasis
are known is selected.
OUTPUT:
- components in the basis
basis
, as an instance of the classComponents
, or, for the identity automorphism, of the subclassKroneckerDelta
EXAMPLES:
Components of an automorphism on 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.components(e) 2-indices components w.r.t. Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring sage: a.components(e)[:] [-1 0 0] [ 0 1 2] [ 0 1 3]
Since e is the module’s default basis, it can be omitted:
sage: a.components() is a.components(e) True
A shortcut is
a.comp()
:sage: a.comp() is a.components() True sage: a.comp(e) is a.components() True
Components in another basis:
sage: f1 = -e[2] sage: f2 = 4*e[1] + 3*e[3] sage: f3 = 7*e[1] + 5*e[3] sage: f = M.basis('f', from_family=(f1,f2,f3)) sage: a.components(f) 2-indices components w.r.t. Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring sage: a.components(f)[:] [ 1 -6 -10] [ -7 83 140] [ 4 -48 -81]
Some 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
Components of the identity map:
sage: id = M.identity_map() sage: id.components(e) Kronecker delta of size 3x3 sage: id.components(e)[:] [1 0 0] [0 1 0] [0 0 1] sage: id.components(f) Kronecker delta of size 3x3 sage: id.components(f)[:] [1 0 0] [0 1 0] [0 0 1]
-
components
(basis=None, from_basis=None)¶ Return the components of
self
w.r.t to a given module basis.If the components are not known already, they are computed by the tensor change-of-basis formula from components in another basis.
INPUT:
basis
– (default:None
) basis in which the components are required; if none is provided, the components are assumed to refer to the module’s default basisfrom_basis
– (default:None
) basis from which the required components are computed, via the tensor change-of-basis formula, if they are not known already in the basisbasis
; if none, a basis from which both the components and a change-of-basis tobasis
are known is selected.
OUTPUT:
- components in the basis
basis
, as an instance of the classComponents
, or, for the identity automorphism, of the subclassKroneckerDelta
EXAMPLES:
Components of an automorphism on 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.components(e) 2-indices components w.r.t. Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring sage: a.components(e)[:] [-1 0 0] [ 0 1 2] [ 0 1 3]
Since e is the module’s default basis, it can be omitted:
sage: a.components() is a.components(e) True
A shortcut is
a.comp()
:sage: a.comp() is a.components() True sage: a.comp(e) is a.components() True
Components in another basis:
sage: f1 = -e[2] sage: f2 = 4*e[1] + 3*e[3] sage: f3 = 7*e[1] + 5*e[3] sage: f = M.basis('f', from_family=(f1,f2,f3)) sage: a.components(f) 2-indices components w.r.t. Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring sage: a.components(f)[:] [ 1 -6 -10] [ -7 83 140] [ 4 -48 -81]
Some 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
Components of the identity map:
sage: id = M.identity_map() sage: id.components(e) Kronecker delta of size 3x3 sage: id.components(e)[:] [1 0 0] [0 1 0] [0 0 1] sage: id.components(f) Kronecker delta of size 3x3 sage: id.components(f)[:] [1 0 0] [0 1 0] [0 0 1]
-
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
- element of the base ring of the module on which
-
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
- instance of
-
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 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.
EXAMPLE:
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): ... TypeError: the components of the identity map cannot be changed
Indeed, the components are automatically set by a call to
comp()
: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
- element of the base ring of the module on which