Free module morphisms - Tensors on free modules of finite rank

Skip to content
Back to top
View this page
Edit this page

# Free module morphisms

The class `FiniteRankFreeModuleMorphism` implements homomorphisms between two free modules of finite rank over the same commutative ring.

The subclass `FiniteRankFreeModuleEndomorphism` implements the special case of endomorphisms.

AUTHORS:

- Eric Gourgoulhon, Michal Bejger (2014-2015): initial version

- Matthias Koeppe (2024): add subclass `FiniteRankFreeModuleEndomorphism`

REFERENCES:

- Chap. 13, 14 of R. Godement : Algebra [God1968]

- Chap. 3 of S. Lang : Algebra [Lan2002]

class sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleEndomorphism(parent, matrix_rep, bases=None, name=None, latex_name=None, is_identity=False)

  Bases: `FiniteRankFreeModuleMorphism`

  Endomorphism of a free module of finite rank over a commutative ring.

  An instance of this class is an endomorphism

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

  where \(M\) is a free module of finite rank over a commutative ring \(R\).

  This is a Sage element class, the corresponding parent class being `FreeModuleEndset`.

  INPUT:

  - `parent` – Hom-set Hom(M,M) to which the endomorphism belongs

  - `matrix_rep` – matrix representation of the endomorphism with respect to the basis `bases`; this entry can actually be any material from which a matrix of size rank(N)*rank(M) of elements of \(R\) can be constructed; the columns of the matrix give the images of the basis of \(M\) (see the convention in the example below)

  - `bases` – (default: `None`) pair `(basis_domain, basis_codomain)` defining the matrix representation, `basis_domain` and `basis_codomain` being two bases (typically the same) of the same module \(M\); if `None`, the default basis of \(M\) is used for both.

  - `name` – (default: `None`) string; name given to the endomorphism

  - `latex_name` – (default: `None`) string; LaTeX symbol to denote the endomorphism. If `None`, `name` will be used.

  - `is_identity` – boolean (default: `False`); determines whether the constructed object is the identity endomorphism. If set to `True`, then the entry `matrix_rep` is not used.

  EXAMPLES:

  The identity endomorphism:

  Sage

      sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
      sage: e = M.basis('e')
      sage: Id = End(M).one(); Id
      Identity endomorphism of Rank-3 free module M over the Integer Ring
      sage: Id.parent()
      Set of Morphisms from Rank-3 free module M over the Integer Ring
       to Rank-3 free module M over the Integer Ring
       in Category of finite dimensional modules over Integer Ring
      sage: Id.parent() is End(M)
      True

  Python

      >>> from sage.all import *
      >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
      >>> e = M.basis('e')
      >>> Id = End(M).one(); Id
      Identity endomorphism of Rank-3 free module M over the Integer Ring
      >>> Id.parent()
      Set of Morphisms from Rank-3 free module M over the Integer Ring
       to Rank-3 free module M over the Integer Ring
       in Category of finite dimensional modules over Integer Ring
      >>> Id.parent() is End(M)
      True

  The matrix of `Id` with respect to the basis `e` is of course the identity matrix:

  Sage

      sage: Id.matrix(e)
      [1 0 0]
      [0 1 0]
      [0 0 1]

  [Python]

      >>> from sage.all import *
      >>> Id.matrix(e)
      [1 0 0]
      [0 1 0]
      [0 0 1]

  The identity acting on a module element:

  Sage

      sage: v = M([-2,1,4], basis=e, name='v'); v.display()
      v = -2 e_0 + e_1 + 4 e_2
      sage: Id(v) is v
      True

  Python

      >>> from sage.all import *
      >>> v = M([-Integer(2),Integer(1),Integer(4)], basis=e, name='v'); v.display()
      v = -2 e_0 + e_1 + 4 e_2
      >>> Id(v) is v
      True

  characteristic_polynomial()

    Return the characteristic polynomial of `self`.

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

    INPUT:

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

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: e = M.basis('e')
        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        sage: phi.characteristic_polynomial()
        x^3 - 15*x^2 - 18*x
        sage: phi.charpoly()
        x^3 - 15*x^2 - 18*x
        sage: phi.charpoly('T')
        T^3 - 15*T^2 - 18*T

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> e = M.basis('e')
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        >>> phi.characteristic_polynomial()
        x^3 - 15*x^2 - 18*x
        >>> phi.charpoly()
        x^3 - 15*x^2 - 18*x
        >>> phi.charpoly('T')
        T^3 - 15*T^2 - 18*T

  charpoly()

    alias of `characteristic_polynomial()`.

  det()

    Return the determinant of `self`.

    OUTPUT:

    - element of the base ring of the modules on which `self` is defined, equal to the determinant of `self`.

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: e = M.basis('e')
        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        sage: phi.det()
        0
        sage: det(phi)
        0

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> e = M.basis('e')
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        >>> phi.det()
        0
        >>> det(phi)
        0

  determinant()

    alias of `det()`.

  fcp()

    Return the factorization of the characteristic polynomial of `self`.

    INPUT:

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

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: e = M.basis('e')
        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        sage: phi.fcp()                                                             # needs sage.libs.pari
        x * (x^2 - 15*x - 18)
        sage: phi.fcp('T')                                                          # needs sage.libs.pari
        T * (T^2 - 15*T - 18)

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> e = M.basis('e')
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        >>> phi.fcp()                                                             # needs sage.libs.pari
        x * (x^2 - 15*x - 18)
        >>> phi.fcp('T')                                                          # needs sage.libs.pari
        T * (T^2 - 15*T - 18)

  minimal_polynomial()

    Return the minimal polynomial of `self`.

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

    INPUT:

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

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: e = M.basis('e')
        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        sage: phi.minpoly()                                                         # needs sage.libs.pari
        x^3 - 15*x^2 - 18*x
        sage: phi.minimal_polynomial()                                              # needs sage.libs.pari
        x^3 - 15*x^2 - 18*x
        sage: phi.minimal_polynomial('T')                                           # needs sage.libs.pari
        T^3 - 15*T^2 - 18*T

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> e = M.basis('e')
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        >>> phi.minpoly()                                                         # needs sage.libs.pari
        x^3 - 15*x^2 - 18*x
        >>> phi.minimal_polynomial()                                              # needs sage.libs.pari
        x^3 - 15*x^2 - 18*x
        >>> phi.minimal_polynomial('T')                                           # needs sage.libs.pari
        T^3 - 15*T^2 - 18*T

  minpoly()

    alias of `minimal_polynomial()`.

  trace()

    Return the trace of `self`.

    OUTPUT:

    - element of the base ring of the modules on which `self` is defined, equal to the trace of `self`.

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: e = M.basis('e')
        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        sage: phi.trace()
        15
        sage: id = M.identity_map()
        sage: id.trace()
        3

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> e = M.basis('e')
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.matrix(e)
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]
        >>> phi.trace()
        15
        >>> id = M.identity_map()
        >>> id.trace()
        3

class sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism(parent, matrix_rep, bases=None, name=None, latex_name=None, is_identity=False)

  Bases: `Morphism`

  Homomorphism between free modules of finite rank over a commutative ring.

  An instance of this class is a homomorphism

  \[\phi:\ M \longrightarrow N,\]

  where \(M\) and \(N\) are two free modules of finite rank over the same commutative ring \(R\).

  This is a Sage element class, the corresponding parent class being `FreeModuleHomset`.

  For the special case of endomorphisms (\(M=N\)), use the subclass `FiniteRankFreeModuleEndomorphism`.

  INPUT:

  - `parent` – Hom-set Hom(M,N) to which the homomorphism belongs

  - `matrix_rep` – matrix representation of the homomorphism with respect to the bases `bases`; this entry can actually be any material from which a matrix of size rank(N)*rank(M) of elements of \(R\) can be constructed; the columns of the matrix give the images of the basis of \(M\) (see the convention in the example below)

  - `bases` – (default: `None`) pair (basis_M, basis_N) defining the matrix representation, basis_M being a basis of module \(M\) and basis_N a basis of module \(N\) ; if None the pair formed by the default bases of each module is assumed.

  - `name` – (default: `None`) string; name given to the homomorphism

  - `latex_name` – (default: `None`) string; LaTeX symbol to denote the homomorphism. If `None`, `name` will be used.

  EXAMPLES:

  A homomorphism between two free modules over \(\ZZ\) is constructed as an element of the corresponding hom-set, by means of the function `__call__`:

  Sage

      sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
      sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
      sage: e = M.basis('e') ; f = N.basis('f')
      sage: H = Hom(M,N) ; H
      Set of Morphisms from Rank-3 free module M over the Integer Ring
       to Rank-2 free module N over the Integer Ring
       in Category of finite dimensional modules over Integer Ring
      sage: phi = H([[2,-1,3], [1,0,-4]], name='phi', latex_name=r'\phi') ; phi
      Generic morphism:
        From: Rank-3 free module M over the Integer Ring
        To:   Rank-2 free module N over the Integer Ring

  Python

      >>> from sage.all import *
      >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
      >>> N = FiniteRankFreeModule(ZZ, Integer(2), name='N')
      >>> e = M.basis('e') ; f = N.basis('f')
      >>> H = Hom(M,N) ; H
      Set of Morphisms from Rank-3 free module M over the Integer Ring
       to Rank-2 free module N over the Integer Ring
       in Category of finite dimensional modules over Integer Ring
      >>> phi = H([[Integer(2),-Integer(1),Integer(3)], [Integer(1),Integer(0),-Integer(4)]], name='phi', latex_name=r'\phi') ; phi
      Generic morphism:
        From: Rank-3 free module M over the Integer Ring
        To:   Rank-2 free module N over the Integer Ring

  Since no bases have been specified in the argument list, the provided matrix is relative to the default bases of modules M and N, so that the above is equivalent to:

  Sage

      sage: phi = H([[2,-1,3], [1,0,-4]], bases=(e,f), name='phi',
      ....:         latex_name=r'\phi') ; phi
      Generic morphism:
        From: Rank-3 free module M over the Integer Ring
        To:   Rank-2 free module N over the Integer Ring

  [Python]

      >>> from sage.all import *
      >>> phi = H([[Integer(2),-Integer(1),Integer(3)], [Integer(1),Integer(0),-Integer(4)]], bases=(e,f), name='phi',
      ...         latex_name=r'\phi') ; phi
      Generic morphism:
        From: Rank-3 free module M over the Integer Ring
        To:   Rank-2 free module N over the Integer Ring

  An alternative way to construct a homomorphism is to call the method `hom()` on the domain:

  Sage

      sage: phi = M.hom(N, [[2,-1,3], [1,0,-4]], bases=(e,f), name='phi',
      ....:             latex_name=r'\phi') ; phi
      Generic morphism:
        From: Rank-3 free module M over the Integer Ring
        To:   Rank-2 free module N over the Integer Ring

  Python

      >>> from sage.all import *
      >>> phi = M.hom(N, [[Integer(2),-Integer(1),Integer(3)], [Integer(1),Integer(0),-Integer(4)]], bases=(e,f), name='phi',
      ...             latex_name=r'\phi') ; phi
      Generic morphism:
        From: Rank-3 free module M over the Integer Ring
        To:   Rank-2 free module N over the Integer Ring

  The parent of a homomorphism is of course the corresponding hom-set:

  Sage

      sage: phi.parent() is H
      True
      sage: phi.parent() is Hom(M,N)
      True

  [Python]

      >>> from sage.all import *
      >>> phi.parent() is H
      True
      >>> phi.parent() is Hom(M,N)
      True

  Due to Sage’s category scheme, the actual class of the homomorphism `phi` is a derived class of `FiniteRankFreeModuleMorphism`:

  Sage

      sage: type(phi)
      <class 'sage.tensor.modules.free_module_homset.FreeModuleHomset_with_category_with_equality_by_id.element_class'>
      sage: isinstance(phi, sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism)
      True

  Python

      >>> from sage.all import *
      >>> type(phi)
      <class 'sage.tensor.modules.free_module_homset.FreeModuleHomset_with_category_with_equality_by_id.element_class'>
      >>> isinstance(phi, sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism)
      True

  The domain and codomain of the homomorphism are returned respectively by the methods `domain()` and `codomain()`, which are implemented as Sage’s constant functions:

  Sage

      sage: phi.domain()
      Rank-3 free module M over the Integer Ring
      sage: phi.codomain()
      Rank-2 free module N over the Integer Ring
      sage: type(phi.domain)
      <... 'sage.misc.constant_function.ConstantFunction'>

  [Python]

      >>> from sage.all import *
      >>> phi.domain()
      Rank-3 free module M over the Integer Ring
      >>> phi.codomain()
      Rank-2 free module N over the Integer Ring
      >>> type(phi.domain)
      <... 'sage.misc.constant_function.ConstantFunction'>

  The matrix of the homomorphism with respect to a pair of bases is returned by the method `matrix()`:

  Sage

      sage: phi.matrix(e,f)
      [ 2 -1  3]
      [ 1  0 -4]

  Python

      >>> from sage.all import *
      >>> phi.matrix(e,f)
      [ 2 -1  3]
      [ 1  0 -4]

  The convention is that the columns of this matrix give the components of the images of the elements of basis `e` w.r.t basis `f`:

  Sage

      sage: phi(e[0]).display()
      phi(e_0) = 2 f_0 + f_1
      sage: phi(e[1]).display()
      phi(e_1) = -f_0
      sage: phi(e[2]).display()
      phi(e_2) = 3 f_0 - 4 f_1

  [Python]

      >>> from sage.all import *
      >>> phi(e[Integer(0)]).display()
      phi(e_0) = 2 f_0 + f_1
      >>> phi(e[Integer(1)]).display()
      phi(e_1) = -f_0
      >>> phi(e[Integer(2)]).display()
      phi(e_2) = 3 f_0 - 4 f_1

  Test of the module homomorphism laws:

  Sage

      sage: phi(M.zero()) == N.zero()
      True
      sage: u = M([1,2,3], basis=e, name='u') ; u.display()
      u = e_0 + 2 e_1 + 3 e_2
      sage: v = M([-2,1,4], basis=e, name='v') ; v.display()
      v = -2 e_0 + e_1 + 4 e_2
      sage: phi(u).display()
      phi(u) = 9 f_0 - 11 f_1
      sage: phi(v).display()
      phi(v) = 7 f_0 - 18 f_1
      sage: phi(3*u + v).display()
      34 f_0 - 51 f_1
      sage: phi(3*u + v) == 3*phi(u) + phi(v)
      True

  Python

      >>> from sage.all import *
      >>> phi(M.zero()) == N.zero()
      True
      >>> u = M([Integer(1),Integer(2),Integer(3)], basis=e, name='u') ; u.display()
      u = e_0 + 2 e_1 + 3 e_2
      >>> v = M([-Integer(2),Integer(1),Integer(4)], basis=e, name='v') ; v.display()
      v = -2 e_0 + e_1 + 4 e_2
      >>> phi(u).display()
      phi(u) = 9 f_0 - 11 f_1
      >>> phi(v).display()
      phi(v) = 7 f_0 - 18 f_1
      >>> phi(Integer(3)*u + v).display()
      34 f_0 - 51 f_1
      >>> phi(Integer(3)*u + v) == Integer(3)*phi(u) + phi(v)
      True

  display(basis1=None, basis2=None)

    Display `self` as a matrix 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 domain of `self`; if none is provided, the domain’s default basis is assumed

    - `basis2` – (default: `None`) basis of the codomain of `self`; if none is provided, `basis2` is set to `basis1` if `self` is an endomorphism, otherwise, `basis2` is set to the codomain’s default basis.

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
        sage: e = M.basis('e'); f = N.basis('f')
        sage: phi = M.hom(N, [[-1,2,0], [5,1,2]])
        sage: phi.display()     # default bases
            e_0 e_1 e_2
        f_0⎛ -1   2   0⎞
        f_1⎝  5   1   2⎠
        sage: phi.display(e, f)  # given bases
            e_0 e_1 e_2
        f_0⎛ -1   2   0⎞
        f_1⎝  5   1   2⎠

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> N = FiniteRankFreeModule(ZZ, Integer(2), name='N')
        >>> e = M.basis('e'); f = N.basis('f')
        >>> phi = M.hom(N, [[-Integer(1),Integer(2),Integer(0)], [Integer(5),Integer(1),Integer(2)]])
        >>> phi.display()     # default bases
            e_0 e_1 e_2
        f_0⎛ -1   2   0⎞
        f_1⎝  5   1   2⎠
        >>> phi.display(e, f)  # given bases
            e_0 e_1 e_2
        f_0⎛ -1   2   0⎞
        f_1⎝  5   1   2⎠

    Matrix of an endomorphism:

    Sage

        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.display(ep)
             ep_0 ep_1 ep_2
        ep_0⎛   1    2    3⎞
        ep_1⎜   4    5    6⎟
        ep_2⎝   7    8    9⎠
        sage: phi.display(ep, ep)  # same as above
             ep_0 ep_1 ep_2
        ep_0⎛   1    2    3⎞
        ep_1⎜   4    5    6⎟
        ep_2⎝   7    8    9⎠
        sage: phi.display()  # matrix w.r.t to the module's default basis
            e_0 e_1 e_2
        e_0⎛  1  -3   1⎞
        e_1⎜-18  39 -18⎟
        e_2⎝-25  54 -25⎠

    [Python]

        >>> from sage.all import *
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.display(ep)
             ep_0 ep_1 ep_2
        ep_0⎛   1    2    3⎞
        ep_1⎜   4    5    6⎟
        ep_2⎝   7    8    9⎠
        >>> phi.display(ep, ep)  # same as above
             ep_0 ep_1 ep_2
        ep_0⎛   1    2    3⎞
        ep_1⎜   4    5    6⎟
        ep_2⎝   7    8    9⎠
        >>> phi.display()  # matrix w.r.t to the module's default basis
            e_0 e_1 e_2
        e_0⎛  1  -3   1⎞
        e_1⎜-18  39 -18⎟
        e_2⎝-25  54 -25⎠

  is_identity()

    Check whether `self` is the identity morphism.

    EXAMPLES:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
        sage: e = M.basis('e')
        sage: phi = M.endomorphism([[1,0], [0,1]])
        sage: phi.is_identity()
        True
        sage: (phi+phi).is_identity()
        False
        sage: End(M).zero().is_identity()
        False
        sage: a = M.automorphism() ; a[0,1], a[1,0] = 1, -1
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: phi = M.endomorphism([[1,0], [0,1]], basis=ep)
        sage: phi.is_identity()
        True

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(2), name='M')
        >>> e = M.basis('e')
        >>> phi = M.endomorphism([[Integer(1),Integer(0)], [Integer(0),Integer(1)]])
        >>> phi.is_identity()
        True
        >>> (phi+phi).is_identity()
        False
        >>> End(M).zero().is_identity()
        False
        >>> a = M.automorphism() ; a[Integer(0),Integer(1)], a[Integer(1),Integer(0)] = Integer(1), -Integer(1)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> phi = M.endomorphism([[Integer(1),Integer(0)], [Integer(0),Integer(1)]], basis=ep)
        >>> phi.is_identity()
        True

    Example illustrating that the identity can be constructed from a matrix that is not the identity one, provided that it is relative to different bases:

    Sage

        sage: phi = M.hom(M, [[0,1], [-1,0]], bases=(ep,e))
        sage: phi.is_identity()
        True

    [Python]

        >>> from sage.all import *
        >>> phi = M.hom(M, [[Integer(0),Integer(1)], [-Integer(1),Integer(0)]], bases=(ep,e))
        >>> phi.is_identity()
        True

    Of course, if we ask for the matrix in a single basis, it is the identity matrix:

    Sage

        sage: phi.matrix(e)
        [1 0]
        [0 1]
        sage: phi.matrix(ep)
        [1 0]
        [0 1]

    Python

        >>> from sage.all import *
        >>> phi.matrix(e)
        [1 0]
        [0 1]
        >>> phi.matrix(ep)
        [1 0]
        [0 1]

  is_injective()

    Determine whether `self` is injective.

    OUTPUT:

    - `True` if `self` is an injective homomorphism and `False` otherwise

    EXAMPLES:

    Homomorphisms between two \(\ZZ\)-modules:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
        sage: e = M.basis('e') ; f = N.basis('f')
        sage: phi = M.hom(N, [[-1,2,0], [5,1,2]])
        sage: phi.matrix(e,f)
        [-1  2  0]
        [ 5  1  2]
        sage: phi.is_injective()
        False

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> N = FiniteRankFreeModule(ZZ, Integer(2), name='N')
        >>> e = M.basis('e') ; f = N.basis('f')
        >>> phi = M.hom(N, [[-Integer(1),Integer(2),Integer(0)], [Integer(5),Integer(1),Integer(2)]])
        >>> phi.matrix(e,f)
        [-1  2  0]
        [ 5  1  2]
        >>> phi.is_injective()
        False

    Indeed, phi has a non trivial kernel:

    Sage

        sage: phi(4*e[0] + 2*e[1] - 11*e[2]).display()
        0

    [Python]

        >>> from sage.all import *
        >>> phi(Integer(4)*e[Integer(0)] + Integer(2)*e[Integer(1)] - Integer(11)*e[Integer(2)]).display()
        0

    An injective homomorphism:

    Sage

        sage: psi = N.hom(M, [[1,-1], [0,3], [4,-5]])
        sage: psi.matrix(f,e)
        [ 1 -1]
        [ 0  3]
        [ 4 -5]
        sage: psi.is_injective()
        True

    Python

        >>> from sage.all import *
        >>> psi = N.hom(M, [[Integer(1),-Integer(1)], [Integer(0),Integer(3)], [Integer(4),-Integer(5)]])
        >>> psi.matrix(f,e)
        [ 1 -1]
        [ 0  3]
        [ 4 -5]
        >>> psi.is_injective()
        True

    Of course, the identity endomorphism is injective:

    Sage

        sage: End(M).one().is_injective()
        True
        sage: End(N).one().is_injective()
        True

    [Python]

        >>> from sage.all import *
        >>> End(M).one().is_injective()
        True
        >>> End(N).one().is_injective()
        True

  is_surjective()

    Determine whether `self` is surjective.

    OUTPUT:

    - `True` if `self` is a surjective homomorphism and `False` otherwise

    EXAMPLES:

    This method has not been implemented yet:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
        sage: e = M.basis('e') ; f = N.basis('f')
        sage: phi = M.hom(N, [[-1,2,0], [5,1,2]])
        sage: phi.is_surjective()
        Traceback (most recent call last):
        ...
        NotImplementedError: FiniteRankFreeModuleMorphism.is_surjective()
         has not been implemented yet

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> N = FiniteRankFreeModule(ZZ, Integer(2), name='N')
        >>> e = M.basis('e') ; f = N.basis('f')
        >>> phi = M.hom(N, [[-Integer(1),Integer(2),Integer(0)], [Integer(5),Integer(1),Integer(2)]])
        >>> phi.is_surjective()
        Traceback (most recent call last):
        ...
        NotImplementedError: FiniteRankFreeModuleMorphism.is_surjective()
         has not been implemented yet

    except for the identity endomorphism (!):

    Sage

        sage: End(M).one().is_surjective()
        True
        sage: End(N).one().is_surjective()
        True

    [Python]

        >>> from sage.all import *
        >>> End(M).one().is_surjective()
        True
        >>> End(N).one().is_surjective()
        True

  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 domain of `self`; if none is provided, the domain’s default basis is assumed

    - `basis2` – (default: `None`) basis of the codomain of `self`; if none is provided, `basis2` is set to `basis1` if `self` is an endomorphism, otherwise, `basis2` is set to the codomain’s default basis.

    OUTPUT:

    - the matrix representing the homomorphism `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:

    Matrix of a homomorphism between two \(\ZZ\)-modules:

    Sage

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
        sage: e = M.basis('e') ; f = N.basis('f')
        sage: phi = M.hom(N, [[-1,2,0], [5,1,2]])
        sage: phi.matrix()     # default bases
        [-1  2  0]
        [ 5  1  2]
        sage: phi.matrix(e, f)  # given bases
        [-1  2  0]
        [ 5  1  2]
        sage: type(phi.matrix())                                                    # needs sage.libs.flint
        <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>

    Python

        >>> from sage.all import *
        >>> M = FiniteRankFreeModule(ZZ, Integer(3), name='M')
        >>> N = FiniteRankFreeModule(ZZ, Integer(2), name='N')
        >>> e = M.basis('e') ; f = N.basis('f')
        >>> phi = M.hom(N, [[-Integer(1),Integer(2),Integer(0)], [Integer(5),Integer(1),Integer(2)]])
        >>> phi.matrix()     # default bases
        [-1  2  0]
        [ 5  1  2]
        >>> phi.matrix(e, f)  # given bases
        [-1  2  0]
        [ 5  1  2]
        >>> type(phi.matrix())                                                    # needs sage.libs.flint
        <class 'sage.matrix.matrix_integer_dense.Matrix_integer_dense'>

    Matrix in bases different from those in which the homomorphism has been defined:

    Sage

        sage: a = M.automorphism(matrix=[[-1,0,0],[0,1,2],[0,1,3]], basis=e)
        sage: ep = e.new_basis(a, 'ep', latex_symbol="e'")
        sage: b = N.automorphism(matrix=[[3,5],[4,7]], basis=f)
        sage: fp = f.new_basis(b, 'fp', latex_symbol="f'")
        sage: phi.matrix(ep, fp)
        [ 32  -1 -12]
        [-19   1   8]

    [Python]

        >>> from sage.all import *
        >>> a = M.automorphism(matrix=[[-Integer(1),Integer(0),Integer(0)],[Integer(0),Integer(1),Integer(2)],[Integer(0),Integer(1),Integer(3)]], basis=e)
        >>> ep = e.new_basis(a, 'ep', latex_symbol="e'")
        >>> b = N.automorphism(matrix=[[Integer(3),Integer(5)],[Integer(4),Integer(7)]], basis=f)
        >>> fp = f.new_basis(b, 'fp', latex_symbol="f'")
        >>> phi.matrix(ep, fp)
        [ 32  -1 -12]
        [-19   1   8]

    Check of the change-of-basis formula:

    Sage

        sage: phi.matrix(ep, fp) == (b^(-1)).matrix(f) * phi.matrix(e,f) * a.matrix(e)
        True

    Python

        >>> from sage.all import *
        >>> phi.matrix(ep, fp) == (b**(-Integer(1))).matrix(f) * phi.matrix(e,f) * a.matrix(e)
        True

    Single change of basis:

    Sage

        sage: phi.matrix(ep, f)
        [ 1  2  4]
        [-5  3  8]
        sage: phi.matrix(ep,f) == phi.matrix(e,f) * a.matrix(e)
        True
        sage: phi.matrix(e, fp)
        [-32   9 -10]
        [ 19  -5   6]
        sage: phi.matrix(e, fp) == (b^(-1)).matrix(f) * phi.matrix(e,f)
        True

    [Python]

        >>> from sage.all import *
        >>> phi.matrix(ep, f)
        [ 1  2  4]
        [-5  3  8]
        >>> phi.matrix(ep,f) == phi.matrix(e,f) * a.matrix(e)
        True
        >>> phi.matrix(e, fp)
        [-32   9 -10]
        [ 19  -5   6]
        >>> phi.matrix(e, fp) == (b**(-Integer(1))).matrix(f) * phi.matrix(e,f)
        True

    Matrix of an endomorphism:

    Sage

        sage: phi = M.endomorphism([[1,2,3], [4,5,6], [7,8,9]], basis=ep)
        sage: phi.matrix(ep)
        [1 2 3]
        [4 5 6]
        [7 8 9]
        sage: phi.matrix(ep,ep)  # same as above
        [1 2 3]
        [4 5 6]
        [7 8 9]
        sage: phi.matrix()  # matrix w.r.t to the module's default basis
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]

    Python

        >>> from sage.all import *
        >>> phi = M.endomorphism([[Integer(1),Integer(2),Integer(3)], [Integer(4),Integer(5),Integer(6)], [Integer(7),Integer(8),Integer(9)]], basis=ep)
        >>> phi.matrix(ep)
        [1 2 3]
        [4 5 6]
        [7 8 9]
        >>> phi.matrix(ep,ep)  # same as above
        [1 2 3]
        [4 5 6]
        [7 8 9]
        >>> phi.matrix()  # matrix w.r.t to the module's default basis
        [  1  -3   1]
        [-18  39 -18]
        [-25  54 -25]