Free module automorphisms#

Given a free module \(M\) of finite rank over a commutative ring \(R\), an automorphism of \(M\) is a map

\[\phi:\ M \longrightarrow M\]

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)[source]#

Bases: FreeModuleTensor, 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 and MultiplicativeGroupElement.

INPUT:

  • fmodule – free module \(M\) of finite rank over a commutative ring \(R\), as an instance of FiniteRankFreeModule

  • name – (default: None) name given to the automorphism

  • latex_name – (default: None) LaTeX symbol to denote the automorphism; if none is provided, the LaTeX symbol is set to name

  • 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
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(2), name='M', start_index=Integer(1))
>>> a = M.automorphism(name='a', latex_name=r'\alpha') ; a
Automorphism a of the Rank-2 free module M over the Integer Ring
>>> a.parent()
General linear group of the Rank-2 free module M over the Integer Ring
>>> a.parent() is M.general_linear_group()
True
>>> latex(a)
\alpha

Setting the components of a w.r.t. a basis of module M:

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
>>> from sage.all import *
>>> e = M.basis('e') ; e
Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
>>> a[:] = [[Integer(1),Integer(2)],[Integer(1),Integer(3)]]
>>> a.matrix(e)
[1 2]
[1 3]
>>> a(e[Integer(1)]).display()
a(e_1) = e_1 + e_2
>>> a(e[Integer(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]
>>> from sage.all import *
>>> a = M.automorphism(matrix=[[Integer(1),Integer(2)],[Integer(1),Integer(3)]], basis=e, name='a',
...                    latex_name=r'\alpha') ; a
Automorphism a of the Rank-2 free module M over the Integer Ring
>>> 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
>>> from sage.all import *
>>> a == M.automorphism(matrix=[[Integer(1),Integer(2)],[Integer(1),Integer(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]
>>> from sage.all import *
>>> f = M.basis('f', from_family=(Integer(3)*e[Integer(1)]+Integer(4)*e[Integer(2)], Integer(5)*e[Integer(1)]+Integer(7)*e[Integer(2)])) ; f
Basis (f_1,f_2) on the Rank-2 free module M over the Integer Ring
>>> 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
>>> from sage.all import *
>>> a.tensor_type()
(1, 1)
>>> 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
>>> from sage.all import *
>>> a.display(e)
a = e_1⊗e^1 + 2 e_1⊗e^2 + e_2⊗e^1 + 3 e_2⊗e^2
>>> 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
>>> from sage.all import *
>>> v = M([-Integer(2),Integer(3)], name='v') ; v
Element v of the Rank-2 free module M over the Integer Ring
>>> a(v)
Element a(v) of the Rank-2 free module M over the Integer Ring
>>> 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
>>> from sage.all import *
>>> b = M.automorphism([[Integer(0),Integer(1)],[-Integer(1),Integer(0)]], name='b') ; b
Automorphism b of the Rank-2 free module M over the Integer Ring
>>> b.matrix(e)
[ 0  1]
[-1  0]
>>> b(e[Integer(1)]).display()
b(e_1) = -e_2
>>> b(e[Integer(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
>>> from sage.all import *
>>> s = a*b ; s
Automorphism of the Rank-2 free module M over the Integer Ring
>>> s(v) == a(b(v))
True
>>> s.matrix(f)
[ 11  19]
[ -7 -12]
>>> s.matrix(f) == a.matrix(f) * b.matrix(f)
True

It is not commutative:

sage: a*b != b*a
True
>>> from sage.all import *
>>> a*b != b*a
True

In other words, the parent of a and b, i.e. the group \(\mathrm{GL}(M)\), is not abelian:

sage: M.general_linear_group() in CommutativeAdditiveGroups()
False
>>> from sage.all import *
>>> 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
>>> from sage.all import *
>>> id = M.identity_map() ; id
Identity map of the Rank-2 free module M over the Integer Ring
>>> id.parent()
General linear group of the Rank-2 free module M over the Integer Ring
>>> id(v) == v
True
>>> id.matrix(f)
[1 0]
[0 1]
>>> id*a == a
True
>>> 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
>>> from sage.all import *
>>> a.inverse()
Automorphism a^(-1) of the Rank-2 free module M over the Integer Ring
>>> a.inverse() is ~a
True
>>> a.inverse() is a**(-Integer(1))
True
>>> (a**(-Integer(1))).matrix(e)
[ 3 -2]
[-1  1]
>>> a*a**(-Integer(1)) == id
True
>>> a**(-Integer(1))*a == id
True
>>> a**(-Integer(1))*s == b
True
>>> (a**(-Integer(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
>>> from sage.all import *
>>> M.change_of_basis(e,f)
Automorphism of the Rank-2 free module M over the Integer Ring
>>> M.change_of_basis(e,f).parent()
General linear group of the Rank-2 free module M over the Integer Ring
>>> M.change_of_basis(e,f).matrix(e)
[3 5]
[4 7]
>>> 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
>>> from sage.all import *
>>> -a
Automorphism -a of the Rank-2 free module M over the Integer Ring
>>> (-a).parent()
General linear group of the Rank-2 free module M over the Integer Ring
>>> (-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]
)
>>> from sage.all import *
>>> s = a + b ; s
Type-(1,1) tensor a+b on the Rank-2 free module M over the Integer Ring
>>> s.parent()
Free module of type-(1,1) tensors on the Rank-2 free module M over the
 Integer Ring
>>> 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
>>> from sage.all import *
>>> s = End(M)(a+b) ; s
Generic endomorphism of Rank-2 free module M over the Integer Ring
>>> s(v) == a(v) + b(v)
True
>>> s.matrix(e) == a.matrix(e) + b.matrix(e)
True
>>> s.matrix(f) == a.matrix(f) + b.matrix(f)
True
add_comp(basis=None)[source]#

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]]
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism(name='a')
>>> a[e,:] = [[Integer(1),Integer(0),Integer(0)],[Integer(0),-Integer(1),Integer(2)],[Integer(0),Integer(1),-Integer(3)]]
>>> f = M.basis('f', from_family=(-e[Integer(0)], Integer(3)*e[Integer(1)]+Integer(4)*e[Integer(2)],
...                               Integer(5)*e[Integer(1)]+Integer(7)*e[Integer(2)])) ; f
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer
 Ring
>>> a.add_comp(f)[:] = [[Integer(1),Integer(0),Integer(0)], [Integer(0), Integer(80), Integer(143)], [Integer(0), -Integer(47), -Integer(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}
>>> from sage.all import *
>>> 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
>>> from sage.all import *
>>> id = M.identity_map()
>>> 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
>>> from sage.all import *
>>> id.comp(e)
Kronecker delta of size 3x3
>>> id.comp(f)
Kronecker delta of size 3x3
characteristic_polynomial()[source]#

Return the characteristic polynomial of self.

characteristic_polynomial() and charpoly() are the same method.

INPUT:

  • var – string (default: 'x'); a variable name

EXAMPLES:

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[1,1],[0,2]], name='a')
sage: a.matrix(e)
[1 1]
[0 2]
sage: a.characteristic_polynomial()
x^2 - 3*x + 2
sage: a.charpoly()
x^2 - 3*x + 2
sage: a.charpoly('T')
T^2 - 3*T + 2
>>> from sage.all import *
>>> M = FiniteRankFreeModule(QQ, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(1),Integer(1)],[Integer(0),Integer(2)]], name='a')
>>> a.matrix(e)
[1 1]
[0 2]
>>> a.characteristic_polynomial()
x^2 - 3*x + 2
>>> a.charpoly()
x^2 - 3*x + 2
>>> a.charpoly('T')
T^2 - 3*T + 2
charpoly()[source]#

Return the characteristic polynomial of self.

characteristic_polynomial() and charpoly() are the same method.

INPUT:

  • var – string (default: 'x'); a variable name

EXAMPLES:

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[1,1],[0,2]], name='a')
sage: a.matrix(e)
[1 1]
[0 2]
sage: a.characteristic_polynomial()
x^2 - 3*x + 2
sage: a.charpoly()
x^2 - 3*x + 2
sage: a.charpoly('T')
T^2 - 3*T + 2
>>> from sage.all import *
>>> M = FiniteRankFreeModule(QQ, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(1),Integer(1)],[Integer(0),Integer(2)]], name='a')
>>> a.matrix(e)
[1 1]
[0 2]
>>> a.characteristic_polynomial()
x^2 - 3*x + 2
>>> a.charpoly()
x^2 - 3*x + 2
>>> a.charpoly('T')
T^2 - 3*T + 2
det()[source]#

Return the determinant of self.

OUTPUT:

  • element of the base ring of the module on which self is defined, equal to the determinant of self.

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
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(4),Integer(7)],[Integer(3),Integer(5)]], name='a')
>>> a.matrix(e)
[4 7]
[3 5]
>>> a.det()
-1
>>> det(a)
-1
>>> ~a.det()  # determinant of the inverse automorphism
-1
>>> id = M.identity_map()
>>> id.det()
1
determinant()[source]#

Return the determinant of self.

OUTPUT:

  • element of the base ring of the module on which self is defined, equal to the determinant of self.

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
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(4),Integer(7)],[Integer(3),Integer(5)]], name='a')
>>> a.matrix(e)
[4 7]
[3 5]
>>> a.det()
-1
>>> det(a)
-1
>>> ~a.det()  # determinant of the inverse automorphism
-1
>>> id = M.identity_map()
>>> id.det()
1
fcp()[source]#

Return the factorization of the characteristic polynomial of self.

INPUT:

  • var – string (default: 'x'); a variable name

EXAMPLES:

sage: M = FiniteRankFreeModule(QQ, 2, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[1,1],[0,2]], name='a')
sage: a.matrix(e)
[1 1]
[0 2]
sage: a.fcp()                                                               # needs sage.libs.pari
(x - 2) * (x - 1)
sage: a.fcp('T')                                                            # needs sage.libs.pari
(T - 2) * (T - 1)
>>> from sage.all import *
>>> M = FiniteRankFreeModule(QQ, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(1),Integer(1)],[Integer(0),Integer(2)]], name='a')
>>> a.matrix(e)
[1 1]
[0 2]
>>> a.fcp()                                                               # needs sage.libs.pari
(x - 2) * (x - 1)
>>> a.fcp('T')                                                            # needs sage.libs.pari
(T - 2) * (T - 1)
inverse()[source]#

Return the inverse automorphism.

OUTPUT:

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
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism(name='a')
>>> a[e,:] = [[Integer(1),Integer(0),Integer(0)],[Integer(0),-Integer(1),Integer(2)],[Integer(0),Integer(1),-Integer(3)]]
>>> a.inverse()
Automorphism a^(-1) of the Rank-3 free module M over the Integer
 Ring
>>> 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
>>> from sage.all import *
>>> a.inverse() * a
Identity map of the Rank-3 free module M over the Integer Ring
>>> a * a.inverse()
Identity map of the Rank-3 free module M over the Integer Ring
>>> 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
>>> from sage.all import *
>>> a.inverse().matrix(e)
[ 1  0  0]
[ 0 -3 -2]
[ 0 -1 -1]
>>> a.inverse().matrix(e) == (a.matrix(e))**(-Integer(1))
True

The inverse is cached (as long as a is not modified):

sage: a.inverse() is a.inverse()
True
>>> from sage.all import *
>>> 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]
>>> from sage.all import *
>>> a[Integer(0),Integer(0)] = -Integer(1)
>>> a.matrix(e)
[-1  0  0]
[ 0 -1  2]
[ 0  1 -3]
>>> 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
>>> from sage.all import *
>>> ~a is a.inverse()
True
>>> (a)**(-Integer(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
>>> from sage.all import *
>>> id = M.identity_map()
>>> id.inverse() is id
True

and we have:

sage: a*(a)^(-1) == id
True
sage: (a)^(-1)*a == id
True
>>> from sage.all import *
>>> a*(a)**(-Integer(1)) == id
True
>>> (a)**(-Integer(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
>>> from sage.all import *
>>> c = M.automorphism(name='a^(-1)*b')
>>> c[e,:] = [[Integer(1),Integer(0),Integer(0)],[Integer(0),-Integer(1),Integer(1)],[Integer(0),Integer(2),-Integer(1)]]
>>> c.inverse()
Automorphism (a^(-1)*b)^(-1) of the Rank-3 free module M over the
 Integer Ring
matrix(basis1=None, basis2=None)[source]#

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 which self is defined; if none is provided, the module’s default basis is assumed

  • basis2 – (default: None) basis of the free module on which self is defined; if none is provided, basis2 is set to basis1

OUTPUT:

  • the matrix representing the automorphism self w.r.t to bases basis1 and basis2; more precisely, the columns of this matrix are formed by the components w.r.t. basis2 of the images of the elements of basis1.

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]
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M', start_index=Integer(1))
>>> e = M.basis('e')
>>> a = M.automorphism([[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], name='a')
>>> a.matrix(e)
[-1  0  0]
[ 0  1  2]
[ 0  1  3]
>>> a.matrix()
[-1  0  0]
[ 0  1  2]
[ 0  1  3]
>>> f = M.basis('f', from_family=(-e[Integer(2)], Integer(4)*e[Integer(1)]+Integer(3)*e[Integer(3)],  Integer(7)*e[Integer(1)]+Integer(5)*e[Integer(3)])) ; f
Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring
>>> 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
>>> from sage.all import *
>>> a(f[Integer(1)]).display(f)
a(f_1) = f_1 - 7 f_2 + 4 f_3
>>> a(f[Integer(2)]).display(f)
a(f_2) = -6 f_1 + 83 f_2 - 48 f_3
>>> a(f[Integer(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
>>> from sage.all import *
>>> P = M.change_of_basis(e,f).matrix(e)
>>> a.matrix(f) == P**(-Integer(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
>>> from sage.all import *
>>> b = M.change_of_basis(e,f) ; b
Automorphism of the Rank-3 free module M over the Integer Ring
>>> b.matrix(e)
[ 0  4  7]
[-1  0  0]
[ 0  3  5]
>>> (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
>>> from sage.all import *
>>> (~a).matrix(e)
[-1  0  0]
[ 0  3 -2]
[ 0 -1  1]
>>> (~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]
>>> from sage.all import *
>>> id = M.identity_map()
>>> id.matrix(e)
[1 0 0]
[0 1 0]
[0 0 1]
>>> id.matrix(f)
[1 0 0]
[0 1 0]
[0 0 1]
minimal_polynomial()[source]#

Return the minimal polynomial of self.

minimal_polynomial() and minpoly() are the same method.

INPUT:

  • var – string (default: 'x'); a variable name

EXAMPLES:

sage: M = FiniteRankFreeModule(GF(7), 3, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[0,1,2], [-1,0,3], [2,4,1]], name='a')
sage: a.minpoly()                                                           # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
sage: a.minimal_polynomial()                                                # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
sage: a.minimal_polynomial('T')                                             # needs sage.libs.pari
T^3 + 6*T^2 + 6*T + 1
>>> from sage.all import *
>>> M = FiniteRankFreeModule(GF(Integer(7)), Integer(3), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(0),Integer(1),Integer(2)], [-Integer(1),Integer(0),Integer(3)], [Integer(2),Integer(4),Integer(1)]], name='a')
>>> a.minpoly()                                                           # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
>>> a.minimal_polynomial()                                                # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
>>> a.minimal_polynomial('T')                                             # needs sage.libs.pari
T^3 + 6*T^2 + 6*T + 1
minpoly()[source]#

Return the minimal polynomial of self.

minimal_polynomial() and minpoly() are the same method.

INPUT:

  • var – string (default: 'x'); a variable name

EXAMPLES:

sage: M = FiniteRankFreeModule(GF(7), 3, name='M')
sage: e = M.basis('e')
sage: a = M.automorphism([[0,1,2], [-1,0,3], [2,4,1]], name='a')
sage: a.minpoly()                                                           # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
sage: a.minimal_polynomial()                                                # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
sage: a.minimal_polynomial('T')                                             # needs sage.libs.pari
T^3 + 6*T^2 + 6*T + 1
>>> from sage.all import *
>>> M = FiniteRankFreeModule(GF(Integer(7)), Integer(3), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(0),Integer(1),Integer(2)], [-Integer(1),Integer(0),Integer(3)], [Integer(2),Integer(4),Integer(1)]], name='a')
>>> a.minpoly()                                                           # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
>>> a.minimal_polynomial()                                                # needs sage.libs.pari
x^3 + 6*x^2 + 6*x + 1
>>> a.minimal_polynomial('T')                                             # needs sage.libs.pari
T^3 + 6*T^2 + 6*T + 1
set_comp(basis=None)[source]#

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]
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism(name='a')
>>> 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
>>> a.set_comp(e)[:] = [[Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]]
>>> 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
>>> from sage.all import *
>>> 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]
>>> from sage.all import *
>>> a.set_comp(e)[Integer(0),Integer(0)] = -Integer(1)
>>> 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]
>>> from sage.all import *
>>> a[e,:] = [[Integer(1),Integer(0),Integer(0)],[Integer(0),-Integer(1),Integer(2)],[Integer(0),Integer(1),-Integer(3)]]
>>> a.matrix(e)
[ 1  0  0]
[ 0 -1  2]
[ 0  1 -3]
>>> a[e,Integer(0),Integer(0)] = -Integer(1)
>>> 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 method add_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]]
>>> from sage.all import *
>>> f = M.basis('f', from_family=(-e[Integer(0)], Integer(3)*e[Integer(1)]+Integer(4)*e[Integer(2)],
...                               Integer(5)*e[Integer(1)]+Integer(7)*e[Integer(2)])) ; f
Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer
 Ring
>>> 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}
>>> a.set_comp(f)[:] = [[-Integer(1),Integer(0),Integer(0)], [Integer(0),Integer(1),Integer(0)], [Integer(0),Integer(0),-Integer(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}
>>> from sage.all import *
>>> 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 method comp() or matrix():

sage: a.matrix(e)
[ -1   0   0]
[  0  41 -30]
[  0  56 -41]
>>> from sage.all import *
>>> 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
>>> from sage.all import *
>>> id = M.identity_map()
>>> 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
>>> from sage.all import *
>>> id.comp(e)
Kronecker delta of size 3x3
>>> id.comp(f)
Kronecker delta of size 3x3
trace()[source]#

Return the trace of self.

OUTPUT:

  • element of the base ring of the module on which self is defined, equal to the trace of self.

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
>>> from sage.all import *
>>> M = FiniteRankFreeModule(ZZ, Integer(2), name='M')
>>> e = M.basis('e')
>>> a = M.automorphism([[Integer(4),Integer(7)],[Integer(3),Integer(5)]], name='a')
>>> a.matrix(e)
[4 7]
[3 5]
>>> a.trace()
9
>>> id = M.identity_map()
>>> id.trace()
2