r"""
Free modules of finite rank

The class :class:`FiniteRankFreeModule` implements free modules of finite rank
over a commutative ring.

A *free module of finite rank* over a commutative ring `R` is a module `M` over
`R` that admits a *finite basis*, i.e. a finite family of linearly independent
generators. Since `R` is commutative, it has the invariant basis number
property, so that the rank of the free module `M` is defined uniquely, as the
cardinality of any basis of `M`.

No distinguished basis of `M` is assumed. On the contrary, many bases can be
introduced on the free module along with change-of-basis rules (as module
automorphisms). Each
module element has then various representations over the various bases.

.. NOTE::

    The class :class:`FiniteRankFreeModule` does not inherit from
    class :class:`~sage.modules.free_module.FreeModule_generic`
    nor from class
    :class:`~sage.combinat.free_module.CombinatorialFreeModule`, since
    both classes deal with modules with a *distinguished basis* (see
    details :ref:`below <diff-FreeModule>`). Accordingly, the class
    :class:`FiniteRankFreeModule` inherits directly from the generic class
    :class:`~sage.structure.parent.Parent` with the category set to
    :class:`~sage.categories.modules.Modules` (and not to
    :class:`~sage.categories.modules_with_basis.ModulesWithBasis`).

.. TODO::

    - implement submodules
    - create a FreeModules category (cf. the *TODO* statement in the
      documentation of :class:`~sage.categories.modules.Modules`: *Implement
      a ``FreeModules(R)`` category, when so prompted by a concrete use case*)

AUTHORS:

- Eric Gourgoulhon, Michal Bejger (2014-2015): initial version
- Travis Scrimshaw (2016): category set to ``Modules(ring).FiniteDimensional()``
  (:issue:`20770`)
- Michael Jung (2019): improve treatment of the zero element
- Eric Gourgoulhon (2021): unicode symbols for tensor and exterior products
- Matthias Koeppe (2022): ``FiniteRankFreeModule_abstract``, symmetric powers

REFERENCES:

- Chap. 10 of R. Godement : *Algebra* [God1968]_
- Chap. 3 of S. Lang : *Algebra* [Lan2002]_

EXAMPLES:

Let us define a free module of rank 2 over `\ZZ`::

    sage: M = FiniteRankFreeModule(ZZ, 2, name='M') ; M
    Rank-2 free module M over the Integer Ring
    sage: M.category()
    Category of finite dimensional modules over Integer Ring

We introduce a first basis on ``M``::

    sage: e = M.basis('e') ; e
    Basis (e_0,e_1) on the Rank-2 free module M over the Integer Ring

The elements of the basis are of course module elements::

    sage: e[0]
    Element e_0 of the Rank-2 free module M over the Integer Ring
    sage: e[1]
    Element e_1 of the Rank-2 free module M over the Integer Ring
    sage: e[0].parent()
    Rank-2 free module M over the Integer Ring

We define a module element by its components w.r.t. basis ``e``::

    sage: u = M([2,-3], basis=e, name='u')
    sage: u.display(e)
    u = 2 e_0 - 3 e_1

Module elements can be also be created by arithmetic expressions::

    sage: v = -2*u + 4*e[0] ; v
    Element of the Rank-2 free module M over the Integer Ring
    sage: v.display(e)
    6 e_1
    sage: u == 2*e[0] - 3*e[1]
    True

We define a second basis on ``M`` from a family of linearly independent
elements::

    sage: f = M.basis('f', from_family=(e[0]-e[1], -2*e[0]+3*e[1])) ; f
    Basis (f_0,f_1) on the Rank-2 free module M over the Integer Ring
    sage: f[0].display(e)
    f_0 = e_0 - e_1
    sage: f[1].display(e)
    f_1 = -2 e_0 + 3 e_1

We may of course express the elements of basis ``e`` in terms of basis ``f``::

    sage: e[0].display(f)
    e_0 = 3 f_0 + f_1
    sage: e[1].display(f)
    e_1 = 2 f_0 + f_1

as well as any module element::

    sage: u.display(f)
    u = -f_1
    sage: v.display(f)
    12 f_0 + 6 f_1

The two bases are related by a module automorphism::

    sage: a = M.change_of_basis(e,f) ; a
    Automorphism 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)
    [ 1 -2]
    [-1  3]

Let us check that basis ``f`` is indeed the image of basis ``e`` by ``a``::

    sage: f[0] == a(e[0])
    True
    sage: f[1] == a(e[1])
    True

The reverse change of basis is of course the inverse automorphism::

    sage: M.change_of_basis(f,e) == a^(-1)
    True

We introduce a new module element via its components w.r.t. basis ``f``::

    sage: v = M([2,4], basis=f, name='v')
    sage: v.display(f)
    v = 2 f_0 + 4 f_1

The sum of the two module elements ``u`` and ``v`` can be performed even if
they have been defined on different bases, thanks to the known relation
between the two bases::

    sage: s = u + v ; s
    Element u+v of the Rank-2 free module M over the Integer Ring

We can display the result in either basis::

    sage: s.display(e)
    u+v = -4 e_0 + 7 e_1
    sage: s.display(f)
    u+v = 2 f_0 + 3 f_1

Tensor products of elements are implemented::

    sage: t = u*v ; t
    Type-(2,0) tensor u⊗v on the Rank-2 free module M over the Integer Ring
    sage: t.parent()
    Free module of type-(2,0) tensors on the
     Rank-2 free module M over the Integer Ring
    sage: t.display(e)
    u⊗v = -12 e_0⊗e_0 + 20 e_0⊗e_1 + 18 e_1⊗e_0 - 30 e_1⊗e_1
    sage: t.display(f)
    u⊗v = -2 f_1⊗f_0 - 4 f_1⊗f_1

We can access to tensor components w.r.t. to a given basis via the square
bracket operator::

    sage: t[e,0,1]
    20
    sage: t[f,1,0]
    -2
    sage: u[e,0]
    2
    sage: u[e,:]
    [2, -3]
    sage: u[f,:]
    [0, -1]

The parent of the automorphism ``a`` is the group `\mathrm{GL}(M)`, but
``a`` can also be considered as a tensor of type `(1,1)` on ``M``::

    sage: a.parent()
    General linear group of the Rank-2 free module M over the Integer Ring
    sage: a.tensor_type()
    (1, 1)
    sage: a.display(e)
    e_0⊗e^0 - 2 e_0⊗e^1 - e_1⊗e^0 + 3 e_1⊗e^1
    sage: a.display(f)
    f_0⊗f^0 - 2 f_0⊗f^1 - f_1⊗f^0 + 3 f_1⊗f^1

As such, we can form its tensor product with ``t``, yielding a tensor of
type `(3,1)`::

    sage: t*a
    Type-(3,1) tensor on the Rank-2 free module M over the Integer Ring
    sage: (t*a).display(e)
    -12 e_0⊗e_0⊗e_0⊗e^0 + 24 e_0⊗e_0⊗e_0⊗e^1 + 12 e_0⊗e_0⊗e_1⊗e^0
     - 36 e_0⊗e_0⊗e_1⊗e^1 + 20 e_0⊗e_1⊗e_0⊗e^0 - 40 e_0⊗e_1⊗e_0⊗e^1
     - 20 e_0⊗e_1⊗e_1⊗e^0 + 60 e_0⊗e_1⊗e_1⊗e^1 + 18 e_1⊗e_0⊗e_0⊗e^0
     - 36 e_1⊗e_0⊗e_0⊗e^1 - 18 e_1⊗e_0⊗e_1⊗e^0 + 54 e_1⊗e_0⊗e_1⊗e^1
     - 30 e_1⊗e_1⊗e_0⊗e^0 + 60 e_1⊗e_1⊗e_0⊗e^1 + 30 e_1⊗e_1⊗e_1⊗e^0
     - 90 e_1⊗e_1⊗e_1⊗e^1

The parent of `t\otimes a` is itself a free module of finite rank over `\ZZ`::

        sage: T = (t*a).parent() ; T
        Free module of type-(3,1) tensors on the Rank-2 free module M over the
         Integer Ring
        sage: T.base_ring()
        Integer Ring
        sage: T.rank()
        16

.. _diff-FreeModule:

.. RUBRIC:: Differences between ``FiniteRankFreeModule`` and ``FreeModule``
  (or ``VectorSpace``)

To illustrate the differences, let us create two free modules of rank 3 over
`\ZZ`, one with ``FiniteRankFreeModule`` and the other one with
``FreeModule``::

    sage: M = FiniteRankFreeModule(ZZ, 3, name='M') ; M
    Rank-3 free module M over the Integer Ring
    sage: N = FreeModule(ZZ, 3) ; N
    Ambient free module of rank 3 over the principal ideal domain Integer Ring

The main difference is that ``FreeModule`` returns a free module with a
distinguished basis, while ``FiniteRankFreeModule`` does not::

    sage: N.basis()
    [(1, 0, 0), (0, 1, 0), (0, 0, 1)]
    sage: M.bases()
    []
    sage: M.print_bases()
    No basis has been defined on the Rank-3 free module M over the Integer Ring

This is also revealed by the category of each module::

    sage: M.category()
    Category of finite dimensional modules over Integer Ring
    sage: N.category()
    Category of finite dimensional modules with basis over
     (Dedekind domains and euclidean domains and noetherian rings
     and infinite enumerated sets and metric spaces)

In other words, the module created by ``FreeModule`` is actually `\ZZ^3`,
while, in the absence of any distinguished basis, no *canonical* isomorphism
relates the module created by ``FiniteRankFreeModule`` to `\ZZ^3`::

    sage: N is ZZ^3
    True
    sage: M is ZZ^3
    False
    sage: M == ZZ^3
    False

Because it is `\ZZ^3`, ``N`` is unique, while there may be various modules
of the same rank over the same ring created by ``FiniteRankFreeModule``;
they are then distinguished by their names (actually by the complete
sequence of arguments of ``FiniteRankFreeModule``)::

    sage: N1 = FreeModule(ZZ, 3) ; N1
    Ambient free module of rank 3 over the principal ideal domain Integer Ring
    sage: N1 is N  # FreeModule(ZZ, 3) is unique
    True
    sage: M1 = FiniteRankFreeModule(ZZ, 3, name='M_1') ; M1
    Rank-3 free module M_1 over the Integer Ring
    sage: M1 is M  # M1 and M are different rank-3 modules over ZZ
    False
    sage: M1b = FiniteRankFreeModule(ZZ, 3, name='M_1') ; M1b
    Rank-3 free module M_1 over the Integer Ring
    sage: M1b is M1  # because M1b and M1 have the same name
    True

As illustrated above, various bases can be introduced on the module created by
``FiniteRankFreeModule``::

    sage: e = M.basis('e') ; e
    Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
    sage: f = M.basis('f', from_family=(-e[0], e[1]-e[2], -2*e[1]+3*e[2])) ; f
    Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring
    sage: M.bases()
    [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]

Each element of a basis is accessible via its index::

    sage: e[0]
    Element e_0 of the Rank-3 free module M over the Integer Ring
    sage: e[0].parent()
    Rank-3 free module M over the Integer Ring
    sage: f[1]
    Element f_1 of the Rank-3 free module M over the Integer Ring
    sage: f[1].parent()
    Rank-3 free module M over the Integer Ring

while on module ``N``, the element of the (unique) basis is accessible
directly from the module symbol::

    sage: N.0
    (1, 0, 0)
    sage: N.1
    (0, 1, 0)
    sage: N.0.parent()
    Ambient free module of rank 3 over the principal ideal domain Integer Ring

The arithmetic of elements is similar; the difference lies in the display:
a basis has to be specified for elements of ``M``, while elements of ``N`` are
displayed directly as elements of `\ZZ^3`::

    sage: u = 2*e[0] - 3*e[2] ; u
    Element of the Rank-3 free module M over the Integer Ring
    sage: u.display(e)
    2 e_0 - 3 e_2
    sage: u.display(f)
    -2 f_0 - 6 f_1 - 3 f_2
    sage: u[e,:]
    [2, 0, -3]
    sage: u[f,:]
    [-2, -6, -3]
    sage: v = 2*N.0 - 3*N.2 ; v
    (2, 0, -3)

For the case of ``M``, in order to avoid to specify the basis if the user is
always working with the same basis (e.g. only one basis has been defined),
the concept of *default basis* has been introduced::

    sage: M.default_basis()
    Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
    sage: M.print_bases()
    Bases defined on the Rank-3 free module M over the Integer Ring:
     - (e_0,e_1,e_2) (default basis)
     - (f_0,f_1,f_2)

This is different from the *distinguished basis* of ``N``: it simply means that
the mention of the basis can be omitted in function arguments::

    sage: u.display()  # equivalent to u.display(e)
    2 e_0 - 3 e_2
    sage: u[:]         # equivalent to u[e,:]
    [2, 0, -3]

At any time, the default basis can be changed::

    sage: M.set_default_basis(f)
    sage: u.display()
    -2 f_0 - 6 f_1 - 3 f_2

Another difference between ``FiniteRankFreeModule`` and ``FreeModule`` is that
for the former the range of indices can be specified (by default, it starts
from 0)::

    sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1) ; M
    Rank-3 free module M over the Integer Ring
    sage: e = M.basis('e') ; e  # compare with (e_0,e_1,e_2) above
    Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
    sage: e[1], e[2], e[3]
    (Element e_1 of the Rank-3 free module M over the Integer Ring,
     Element e_2 of the Rank-3 free module M over the Integer Ring,
     Element e_3 of the Rank-3 free module M over the Integer Ring)

All the above holds for ``VectorSpace`` instead of ``FreeModule``: the object
created by ``VectorSpace`` is actually a Cartesian power of the base field::

    sage: V = VectorSpace(QQ,3) ; V
    Vector space of dimension 3 over Rational Field
    sage: V.category()
    Category of finite dimensional vector spaces with basis
     over (number fields and quotient fields and metric spaces)
    sage: V is QQ^3
    True
    sage: V.basis()
    [(1, 0, 0), (0, 1, 0), (0, 0, 1)]

To create a vector space without any distinguished basis, one has to use
``FiniteRankFreeModule``::

    sage: V = FiniteRankFreeModule(QQ, 3, name='V') ; V
    3-dimensional vector space V over the Rational Field
    sage: V.category()
    Category of finite dimensional vector spaces over Rational Field
    sage: V.bases()
    []
    sage: V.print_bases()
    No basis has been defined on the 3-dimensional vector space V over the
     Rational Field

The class :class:`FiniteRankFreeModule` has been created for the needs
of the `SageManifolds project <http://sagemanifolds.obspm.fr/>`_, where
free modules do not have any distinguished basis. Too kinds of free modules
occur in the context of differentiable manifolds (see
`here <http://sagemanifolds.obspm.fr/tensor_modules.html>`_ for more
details):

- the tangent vector space at any point of the manifold (cf.
  :class:`~sage.manifolds.differentiable.tangent_space.TangentSpace`);
- the set of vector fields on a parallelizable open subset `U` of the manifold,
  which is a free module over the algebra of scalar fields on `U` (cf.
  :class:`~sage.manifolds.differentiable.vectorfield_module.VectorFieldFreeModule`).

For instance, without any specific coordinate choice, no basis can be
distinguished in a tangent space.

On the other side, the modules created by ``FreeModule`` have much more
algebraic functionalities than those created by ``FiniteRankFreeModule``. In
particular, submodules have not been implemented yet in
:class:`FiniteRankFreeModule`. Moreover, modules resulting from ``FreeModule``
are tailored to the specific kind of their base ring:

- free module over a commutative ring that is not an integral domain
  (`\ZZ/6\ZZ`)::

    sage: R = IntegerModRing(6) ; R
    Ring of integers modulo 6
    sage: FreeModule(R, 3)
    Ambient free module of rank 3 over Ring of integers modulo 6
    sage: type(FreeModule(R, 3))
    <class 'sage.modules.free_module.FreeModule_ambient_with_category'>

- free module over an integral domain that is not principal (`\ZZ[X]`)::

    sage: R.<X> = ZZ[] ; R
    Univariate Polynomial Ring in X over Integer Ring
    sage: FreeModule(R, 3)
    Ambient free module of rank 3 over the integral domain Univariate
     Polynomial Ring in X over Integer Ring
    sage: type(FreeModule(R, 3))
    <class 'sage.modules.free_module.FreeModule_ambient_domain_with_category'>

- free module over a principal ideal domain (`\ZZ`)::

    sage: R = ZZ ; R
    Integer Ring
    sage: FreeModule(R,3)
    Ambient free module of rank 3 over the principal ideal domain Integer Ring
    sage: type(FreeModule(R, 3))
    <class 'sage.modules.free_module.FreeModule_ambient_pid_with_category'>

On the contrary, all objects constructed with ``FiniteRankFreeModule`` belong
to the same class::

    sage: R = IntegerModRing(6)
    sage: type(FiniteRankFreeModule(R, 3))
    <class 'sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule_with_category'>
    sage: R.<X> = ZZ[]
    sage: type(FiniteRankFreeModule(R, 3))
    <class 'sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule_with_category'>
    sage: R = ZZ
    sage: type(FiniteRankFreeModule(R, 3))
    <class 'sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule_with_category'>


.. RUBRIC:: Differences between ``FiniteRankFreeModule`` and
  ``CombinatorialFreeModule``

An alternative to construct free modules in Sage is
:class:`~sage.combinat.free_module.CombinatorialFreeModule`.
However, as ``FreeModule``, it leads to a module with a distinguished basis::

    sage: N = CombinatorialFreeModule(ZZ, [1,2,3]) ; N
    Free module generated by {1, 2, 3} over Integer Ring
    sage: N.category()
    Category of finite dimensional modules with basis over Integer Ring

The distinguished basis is returned by the method ``basis()``::

    sage: b = N.basis() ; b
    Finite family {1: B[1], 2: B[2], 3: B[3]}
    sage: b[1]
    B[1]
    sage: b[1].parent()
    Free module generated by {1, 2, 3} over Integer Ring

For the free module ``M`` created above with ``FiniteRankFreeModule``, the
method ``basis`` has at least one argument: the symbol string that
specifies which basis is required::

    sage: e = M.basis('e') ; e
    Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
    sage: e[1]
    Element e_1 of the Rank-3 free module M over the Integer Ring
    sage: e[1].parent()
    Rank-3 free module M over the Integer Ring

The arithmetic of elements is similar::

    sage: u = 2*e[1] - 5*e[3] ; u
    Element of the Rank-3 free module M over the Integer Ring
    sage: v = 2*b[1] - 5*b[3] ; v
    2*B[1] - 5*B[3]

One notices that elements of ``N`` are displayed directly in terms of their
expansions on the distinguished basis. For elements of ``M``, one has to use
the method
:meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.display`
in order to specify the basis::

    sage: u.display(e)
    2 e_1 - 5 e_3

The components on the basis are returned by the square bracket operator for
``M`` and by the method ``coefficient`` for ``N``::

    sage: [u[e,i] for i in {1,2,3}]
    [2, 0, -5]
    sage: u[e,:]  # a shortcut for the above
    [2, 0, -5]
    sage: [v.coefficient(i) for i in {1,2,3}]
    [2, 0, -5]
"""
# ******************************************************************************
#       Copyright (C) 2014-2021 Eric Gourgoulhon <eric.gourgoulhon@obspm.fr>
#                     2014-2016 Travis Scrimshaw <tscrimsh@umn.edu>
#                     2015      Michal Bejger <bejger@camk.edu.pl>
#                     2016      Frédéric Chapoton
#                     2020      Michael Jung
#                     2020-2022 Matthias Koeppe
#
#  Distributed under the terms of the GNU General Public License (GPL)
#  as published by the Free Software Foundation; either version 2 of
#  the License, or (at your option) any later version.
#                  https://www.gnu.org/licenses/
# ******************************************************************************
from __future__ import annotations

from typing import Optional, TYPE_CHECKING

from sage.categories.fields import Fields
from sage.categories.homset import Hom
from sage.categories.modules import Modules
from sage.categories.morphism import SetIsomorphism
from sage.categories.rings import Rings
from sage.misc.cachefunc import cached_method
from sage.rings.integer import Integer
from sage.sets.family import Family, TrivialFamily
from sage.structure.parent import Parent
from sage.structure.unique_representation import UniqueRepresentation
from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm
from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement
from sage.tensor.modules.free_module_tensor import FreeModuleTensor
from sage.tensor.modules.reflexive_module import (
    ReflexiveModule_abstract,
    ReflexiveModule_base,
    ReflexiveModule_dual,
)

if TYPE_CHECKING:
    from collections.abc import Generator


class FiniteRankFreeModule_abstract(UniqueRepresentation, ReflexiveModule_abstract):
    r"""
    Abstract base class for free modules of finite rank over a commutative ring.
    """

    def __init__(
        self,
        ring,
        rank,
        name=None,
        latex_name=None,
        category=None,
        ambient=None,
    ):
        r"""
        See :class:`FiniteRankFreeModule` for documentation and examples.

        TESTS::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: TestSuite(M).run()
            sage: e = M.basis('e')
            sage: TestSuite(M).run()
            sage: f = M.basis('f')
            sage: TestSuite(M).run()
        """
        # This duplicates the normalization done in __classcall_private__,
        # but it is needed for various subclasses.
        if ring not in Rings().Commutative():
            raise TypeError("the module base ring must be commutative")
        category = Modules(ring).FiniteDimensional().or_subcategory(category)
        Parent.__init__(self, base=ring, category=category)
        self._ring = ring # same as self._base
        if ambient is None:
            self._ambient_module = self
        else:
            self._ambient_module = ambient
        self._rank = rank
        self._name = name
        # This duplicates the normalization done in __classcall_private__,
        # but it is needed for various subclasses.
        if latex_name is None:
            self._latex_name = self._name
        else:
            self._latex_name = latex_name

    def _latex_(self):
        r"""
        LaTeX representation of ``self``.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M._latex_()
            'M'
            sage: latex(M)
            M
            sage: M1 = FiniteRankFreeModule(ZZ, 3, name='M', latex_name=r'\mathcal{M}')
            sage: M1._latex_()
            '\\mathcal{M}'
            sage: latex(M1)
            \mathcal{M}
        """
        if self._latex_name is None:
            return r'\mbox{' + str(self) + r'}'
        return self._latex_name

    def rank(self) -> int:
        r"""
        Return the rank of the free module ``self``.

        Since the ring over which ``self`` is built is assumed to be
        commutative (and hence has the invariant basis number property), the
        rank is defined uniquely, as the cardinality of any basis of ``self``.

        EXAMPLES:

        Rank of free modules over `\ZZ`::

            sage: M = FiniteRankFreeModule(ZZ, 3)
            sage: M.rank()
            3
            sage: M.tensor_module(0,1).rank()
            3
            sage: M.tensor_module(0,2).rank()
            9
            sage: M.tensor_module(1,0).rank()
            3
            sage: M.tensor_module(1,1).rank()
            9
            sage: M.tensor_module(1,2).rank()
            27
            sage: M.tensor_module(2,2).rank()
            81
        """
        return self._rank

    @cached_method
    def zero(self):
        r"""
        Return the zero element of ``self``.

        EXAMPLES:

        Zero elements of free modules over `\ZZ`::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M.zero()
            Element zero of the Rank-3 free module M over the Integer Ring
            sage: M.zero().parent() is M
            True
            sage: M.zero() is M(0)
            True
            sage: T = M.tensor_module(1,1)
            sage: T.zero()
            Type-(1,1) tensor zero on the Rank-3 free module M over the Integer Ring
            sage: T.zero().parent() is T
            True
            sage: T.zero() is T(0)
            True

        Components of the zero element with respect to some basis::

            sage: e = M.basis('e')
            sage: M.zero()[e,:]
            [0, 0, 0]
            sage: all(M.zero()[e,i] == M.base_ring().zero() for i in M.irange())
            True
            sage: T.zero()[e,:]
            [0 0 0]
            [0 0 0]
            [0 0 0]
            sage: M.tensor_module(1,2).zero()[e,:]
            [[[0, 0, 0], [0, 0, 0], [0, 0, 0]],
             [[0, 0, 0], [0, 0, 0], [0, 0, 0]],
             [[0, 0, 0], [0, 0, 0], [0, 0, 0]]]
        """
        resu = self._element_constructor_(name='zero', latex_name='0')
        for basis in self._known_bases:
            resu._add_comp_unsafe(basis)
            # (since new components are initialized to zero)
        resu._is_zero = True # This element is certainly zero
        resu.set_immutable()
        return resu

    def ambient_module(self): # compatible with sage.modules.free_module.FreeModule_generic
        """
        Return the ambient module associated to this module.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M.ambient_module() is M
            True

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: Sym0123x45M = M.tensor_module(6, 0, sym=((0, 1, 2, 3), (4, 5)))
            sage: T60M = M.tensor_module(6, 0)
            sage: Sym0123x45M.ambient_module() is T60M
            True
        """
        return self._ambient_module

    ambient = ambient_module # compatible with sage.modules.with_basis.subquotient.SubmoduleWithBasis

    def is_submodule(self, other):
        """
        Return ``True`` if ``self`` is a submodule of ``other``.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: N = FiniteRankFreeModule(ZZ, 4, name='N')
            sage: M.is_submodule(M)
            True
            sage: M.is_submodule(N)
            False
        """
        return self == other or self.ambient_module() == other

    def isomorphism_with_fixed_basis(self, basis=None, codomain=None):
        r"""
        Construct the canonical isomorphism from the free module ``self``
        to a free module in which ``basis`` of ``self`` is mapped to the
        distinguished basis of ``codomain``.

        INPUT:

        - ``basis`` -- (default: ``None``) the basis of ``self`` which
          should be mapped to the distinguished basis on ``codomain``;
          if ``None``, the default basis is assumed.
        - ``codomain`` -- (default: ``None``) the codomain of the
          isomorphism represented by a free module within the category
          :class:`~sage.categories.modules_with_basis.ModulesWithBasis` with
          the same rank and base ring as ``self``; if ``None``, a free module
          represented by
          :class:`~sage.combinat.free_module.CombinatorialFreeModule` is
          constructed

        OUTPUT:

        - a module isomorphism represented by
          :class:`~sage.categories.morphism.SetIsomorphism`

        EXAMPLES::

            sage: V = FiniteRankFreeModule(QQ, 3, start_index=1); V
            3-dimensional vector space over the Rational Field
            sage: basis = e = V.basis("e"); basis
            Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the
             Rational Field
            sage: phi_e = V.isomorphism_with_fixed_basis(basis); phi_e
            Generic morphism:
              From: 3-dimensional vector space over the Rational Field
              To:   Free module generated by {1, 2, 3} over Rational Field
            sage: phi_e.codomain().category()
            Category of finite dimensional vector spaces with basis over
             Rational Field
            sage: phi_e(e[1] + 2 * e[2])
            e[1] + 2*e[2]

            sage: abc = V.basis(['a', 'b', 'c'], symbol_dual=['d', 'e', 'f']); abc
            Basis (a,b,c) on the 3-dimensional vector space over the Rational Field
            sage: phi_abc = V.isomorphism_with_fixed_basis(abc); phi_abc
            Generic morphism:
            From: 3-dimensional vector space over the Rational Field
            To:   Free module generated by {1, 2, 3} over Rational Field
            sage: phi_abc(abc[1] + 2 * abc[2])
            B[1] + 2*B[2]

        Providing a codomain::

            sage: W = CombinatorialFreeModule(QQ, ['a', 'b', 'c'])
            sage: phi_eW = V.isomorphism_with_fixed_basis(basis, codomain=W); phi_eW
            Generic morphism:
            From: 3-dimensional vector space over the Rational Field
            To:   Free module generated by {'a', 'b', 'c'} over Rational Field
            sage: phi_eW(e[1] + 2 * e[2])
            B['a'] + 2*B['b']
            sage: ~phi_eW
            Generic morphism:
            From: Free module generated by {'a', 'b', 'c'} over Rational Field
            To:   3-dimensional vector space over the Rational Field
            sage: (~phi_eW)(W.basis()['b']).display()
            e_2

        Providing a :class:`~sage.modules.free_module.Module_free_ambient` as the codomain::

            sage: W = QQ^3
            sage: phi_eW = V.isomorphism_with_fixed_basis(basis, codomain=W); phi_eW
            Generic morphism:
            From: 3-dimensional vector space over the Rational Field
            To:   Vector space of dimension 3 over Rational Field
            sage: phi_eW(e[1] + 2 * e[2])
            (1, 2, 0)

        Sending (1,1)-tensors to matrices::

            sage: T11 = V.tensor_module(1, 1); T11
            Free module of type-(1,1) tensors on the
             3-dimensional vector space over the Rational Field
            sage: e_T11 = T11.basis("e"); e_T11
            Standard basis on the
             Free module of type-(1,1) tensors on the 3-dimensional vector space over the Rational Field
             induced by Basis (e_1,e_2,e_3) on the 3-dimensional vector space over the Rational Field
            sage: W = MatrixSpace(QQ, 3)
            sage: phi_e_T11 = T11.isomorphism_with_fixed_basis(e_T11, codomain=W); phi_e_T11
            Generic morphism:
            From: Free module of type-(1,1) tensors on the
                  3-dimensional vector space over the Rational Field
            To:   Full MatrixSpace of 3 by 3 dense matrices over Rational Field
            sage: t = T11.an_element(); t.display()
            1/2 e_1⊗e^1
            sage: phi_e_T11(t)
            [1/2   0   0]
            [  0   0   0]
            [  0   0   0]
            sage: ~phi_e_T11
            Generic morphism:
            From: Full MatrixSpace of 3 by 3 dense matrices over Rational Field
            To:   Free module of type-(1,1) tensors on the
                  3-dimensional vector space over the Rational Field
            sage: (~phi_e_T11)(W([[0, 1/2, 1/3],
            ....:                 [-1/2, 0, 0],
            ....:                 [-1/3, 0, 0]])).display()
            1/2 e_1⊗e^2 + 1/3 e_1⊗e^3 - 1/2 e_2⊗e^1 - 1/3 e_3⊗e^1

        Sending symmetric bilinear forms to matrices (note that they are currently elements
        of `T^{(0,2)}(M)`, not the symmetric power of `M`)::

            sage: T02 = V.tensor_module(0, 2); T02
            Free module of type-(0,2) tensors on the
             3-dimensional vector space over the Rational Field
            sage: e_T02 = T02.basis("e"); e_T02
            Standard basis on the
             Free module of type-(0,2) tensors on the
              3-dimensional vector space over the Rational Field
             induced by Basis (e_1,e_2,e_3) on the
              3-dimensional vector space over the Rational Field
            sage: W = MatrixSpace(QQ, 3)
            sage: phi_e_T02 = T02.isomorphism_with_fixed_basis(e_T02, codomain=W); phi_e_T02
            Generic morphism:
            From: Free module of type-(0,2) tensors on the
                  3-dimensional vector space over the Rational Field
            To:   Full MatrixSpace of 3 by 3 dense matrices over Rational Field

            sage: a = V.sym_bilinear_form()
            sage: a[1,1], a[1,2], a[1,3] = 1, 2, 3
            sage: a[2,2], a[2,3] = 4, 5
            sage: a[3,3] = 6
            sage: a.display()
            e^1⊗e^1 + 2 e^1⊗e^2 + 3 e^1⊗e^3 + 2 e^2⊗e^1 + 4 e^2⊗e^2 + 5 e^2⊗e^3
             + 3 e^3⊗e^1 + 5 e^3⊗e^2 + 6 e^3⊗e^3
            sage: phi_e_T02(a)
            [1 2 3]
            [2 4 5]
            [3 5 6]

        Same but explicitly in the subspace of symmetric bilinear forms::

            sage: Sym2Vdual = V.dual_symmetric_power(2); Sym2Vdual
            Free module of fully symmetric type-(0,2) tensors on the
             3-dimensional vector space over the Rational Field
            sage: Sym2Vdual.is_submodule(T02)
            True
            sage: Sym2Vdual.rank()
            6
            sage: e_Sym2Vdual = Sym2Vdual.basis("e"); e_Sym2Vdual
            Standard basis on the
             Free module of fully symmetric type-(0,2) tensors on the
              3-dimensional vector space over the Rational Field
             induced by Basis (e_1,e_2,e_3) on the
              3-dimensional vector space over the Rational Field
            sage: W_basis = [phi_e_T02(b) for b in e_Sym2Vdual]; W_basis
            [
            [1 0 0]  [0 1 0]  [0 0 1]  [0 0 0]  [0 0 0]  [0 0 0]
            [0 0 0]  [1 0 0]  [0 0 0]  [0 1 0]  [0 0 1]  [0 0 0]
            [0 0 0], [0 0 0], [1 0 0], [0 0 0], [0 1 0], [0 0 1]
            ]
            sage: W = MatrixSpace(QQ, 3).submodule(W_basis); W
            Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field
            sage: phi_e_Sym2Vdual = Sym2Vdual.isomorphism_with_fixed_basis(e_Sym2Vdual,
            ....:                                                          codomain=W)
            sage: phi_e_Sym2Vdual
            Generic morphism:
              From: Free module of fully symmetric type-(0,2) tensors on the
                    3-dimensional vector space over the Rational Field
              To:   Free module generated by {0, 1, 2, 3, 4, 5} over Rational Field

        Sending tensors to elements of the tensor square of :class:`CombinatorialFreeModule`::

            sage: T20 = V.tensor_module(2, 0); T20
            Free module of type-(2,0) tensors on the
             3-dimensional vector space over the Rational Field
            sage: e_T20 = T02.basis("e"); e_T20
            Standard basis on the
             Free module of type-(0,2) tensors on the
              3-dimensional vector space over the Rational Field
             induced by Basis (e_1,e_2,e_3) on the
              3-dimensional vector space over the Rational Field
            sage: W = CombinatorialFreeModule(QQ, [1, 2, 3]).tensor_square(); W
            Free module generated by {1, 2, 3} over Rational Field
             # Free module generated by {1, 2, 3} over Rational Field
            sage: phi_e_T20 = T20.isomorphism_with_fixed_basis(e_T20, codomain=W); phi_e_T20
            Generic morphism:
            From: Free module of type-(2,0) tensors on the
                  3-dimensional vector space over the Rational Field
            To:   Free module generated by {1, 2, 3} over Rational Field
                  # Free module generated by {1, 2, 3} over Rational Field
            sage: t = T20.an_element(); t.display()
            1/2 e_1⊗e_1
            sage: phi_e_T20(t)
            1/2*B[1] # B[1]

        TESTS::

            sage: V = FiniteRankFreeModule(QQ, 3); V
            3-dimensional vector space over the Rational Field
            sage: e = V.basis("e")
            sage: V.isomorphism_with_fixed_basis(e, codomain=QQ^42)
            Traceback (most recent call last):
            ...
            ValueError: domain and codomain must have the same rank
            sage: V.isomorphism_with_fixed_basis(e, codomain=RR^3)
            Traceback (most recent call last):
            ...
            ValueError: domain and codomain must have the same base ring
        """
        base_ring = self.base_ring()
        if basis is None:
            basis = self.default_basis()
        if codomain is None:
            from sage.combinat.free_module import CombinatorialFreeModule
            if isinstance(basis._symbol, str):
                prefix = basis._symbol
            else:
                prefix = None
            codomain = CombinatorialFreeModule(base_ring, basis.keys(),
                                               prefix=prefix)
        else:
            try:
                codomain_rank = codomain.rank()
            except AttributeError:
                # https://github.com/sagemath/sage/issues/34445: MatrixSpace does not have rank
                codomain_rank = codomain.dimension()
            if codomain_rank != self.rank():
                raise ValueError("domain and codomain must have the same rank")
            if codomain.base_ring() != base_ring:
                raise ValueError("domain and codomain must have the same "
                                 "base ring")

        codomain_basis = Family(codomain.basis())
        if isinstance(codomain_basis, TrivialFamily):
            # assume that codomain basis keys are to be ignored;
            # need them several times, can't keep as generators
            key_pairs = tuple(enumerate(basis.keys()))
            basis_by_codomain_key = basis
        else:
            # assume that the keys of the codomain should be used
            # need them several times, can't keep as generators
            key_pairs = tuple(zip(codomain_basis.keys(), basis.keys()))
            basis_by_codomain_key = {}
            for codomain_key, domain_key in key_pairs:
                basis_by_codomain_key[codomain_key] = basis[domain_key]

        def _isomorphism(x):
            r"""
            Concrete isomorphism from ``self`` to ``codomain``.
            """
            return codomain.sum(x[basis, domain_key] * codomain_basis[codomain_key]
                                for codomain_key, domain_key in key_pairs)

        def _inverse(y):
            r"""
            Concrete isomorphism from ``codomain`` to ``self``.
            """
            return self.linear_combination(
                (basis_by_codomain_key[codomain_key], coefficient)
                for codomain_key, coefficient in y.monomial_coefficients().items())

        category = Modules(self.base_ring())
        homset = Hom(self, codomain, category)
        isomorphism = SetIsomorphism(homset, _isomorphism)
        inverse = SetIsomorphism(homset.reversed(), _inverse)
        isomorphism._set_inverse(inverse)
        inverse._set_inverse(isomorphism)
        return isomorphism

    def _test_isomorphism_with_fixed_basis(self, **options):
        r"""
        Test that the method ``isomorphism_with_fixed_basis`` works correctly.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M._test_isomorphism_with_fixed_basis()
        """
        tester = self._tester(**options)
        try:
            basis = self.basis('test')
        except AttributeError:
            return
        morphism = self.isomorphism_with_fixed_basis(basis)
        tester.assertEqual(morphism.codomain().rank(), self.rank())


class FiniteRankFreeModule(ReflexiveModule_base, FiniteRankFreeModule_abstract):
    r"""
    Free module of finite rank over a commutative ring.

    A *free module of finite rank* over a commutative ring `R` is a module `M`
    over `R` that admits a *finite basis*, i.e. a finite family of linearly
    independent generators. Since `R` is commutative, it has the invariant
    basis number property, so that the rank of the free module `M` is defined
    uniquely, as the cardinality of any basis of `M`.

    No distinguished basis of `M` is assumed. On the contrary, many bases can be
    introduced on the free module along with change-of-basis rules (as module
    automorphisms). Each
    module element has then various representations over the various bases.

    .. NOTE::

        The class :class:`FiniteRankFreeModule` does not inherit from
        class :class:`~sage.modules.free_module.FreeModule_generic`
        nor from class
        :class:`~sage.combinat.free_module.CombinatorialFreeModule`, since
        both classes deal with modules with a *distinguished basis* (see
        details :ref:`above <diff-FreeModule>`).
        Moreover, following the recommendation exposed in :issue:`16427`
        the class :class:`FiniteRankFreeModule` inherits directly from
        :class:`~sage.structure.parent.Parent` (with the category set to
        :class:`~sage.categories.modules.Modules`) and not from the Cython
        class :class:`~sage.modules.module.Module`.

    The class :class:`FiniteRankFreeModule` is a Sage *parent* class,
    the corresponding *element* class being
    :class:`~sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement`.

    INPUT:

    - ``ring`` -- commutative ring `R` over which the free module is
      constructed
    - ``rank`` -- positive integer; rank of the free module
    - ``name`` -- (default: ``None``) string; name given to the free module
    - ``latex_name`` -- (default: ``None``) string;  LaTeX symbol to denote
      the freemodule; if none is provided, it is set to ``name``
    - ``start_index`` -- (default: 0) integer; lower bound of the range of
      indices in bases defined on the free module
    - ``output_formatter`` -- (default: ``None``) function or unbound
      method called to format the output of the tensor components;
      ``output_formatter`` must take 1 or 2 arguments: the first argument
      must be an element of the ring `R` and  the second one, if any, some
      format specification

    EXAMPLES:

    Free module of rank 3 over `\ZZ`::

        sage: FiniteRankFreeModule._clear_cache_() # for doctests only
        sage: M = FiniteRankFreeModule(ZZ, 3) ; M
        Rank-3 free module over the Integer Ring
        sage: M = FiniteRankFreeModule(ZZ, 3, name='M') ; M  # declaration with a name
        Rank-3 free module M over the Integer Ring
        sage: M.category()
        Category of finite dimensional modules over Integer Ring
        sage: M.base_ring()
        Integer Ring
        sage: M.rank()
        3

    If the base ring is a field, the free module is in the category of vector
    spaces::

        sage: V = FiniteRankFreeModule(QQ, 3, name='V') ; V
        3-dimensional vector space V over the Rational Field
        sage: V.category()
        Category of finite dimensional vector spaces over Rational Field

    The LaTeX output is adjusted via the parameter ``latex_name``::

        sage: latex(M)  # the default is the symbol provided in the string ``name``
        M
        sage: M = FiniteRankFreeModule(ZZ, 3, name='M', latex_name=r'\mathcal{M}')
        sage: latex(M)
        \mathcal{M}

    The free module M has no distinguished basis::

        sage: M in ModulesWithBasis(ZZ)
        False
        sage: M in Modules(ZZ)
        True

    In particular, no basis is initialized at the module construction::

        sage: M.print_bases()
        No basis has been defined on the Rank-3 free module M over the Integer Ring
        sage: M.bases()
        []

    Bases have to be introduced by means of the method :meth:`basis`,
    the first defined basis being considered as the *default basis*, meaning
    it can be skipped in function arguments required a basis (this can
    be changed by means of the method :meth:`set_default_basis`)::

        sage: e = M.basis('e') ; e
        Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
        sage: M.default_basis()
        Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring

    A second basis can be created from a family of linearly independent
    elements expressed in terms of basis ``e``::

        sage: f = M.basis('f', from_family=(-e[0], e[1]+e[2], 2*e[1]+3*e[2]))
        sage: f
        Basis (f_0,f_1,f_2) on the Rank-3 free module M over the Integer Ring
        sage: M.print_bases()
        Bases defined on the Rank-3 free module M over the Integer Ring:
         - (e_0,e_1,e_2) (default basis)
         - (f_0,f_1,f_2)
        sage: M.bases()
        [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]

    M is a *parent* object, whose elements are instances of
    :class:`~sage.tensor.modules.free_module_element.FiniteRankFreeModuleElement`
    (actually a dynamically generated subclass of it)::

        sage: v = M.an_element() ; v
        Element of the Rank-3 free module M over the Integer Ring
        sage: from sage.tensor.modules.free_module_element import FiniteRankFreeModuleElement
        sage: isinstance(v, FiniteRankFreeModuleElement)
        True
        sage: v in M
        True
        sage: M.is_parent_of(v)
        True
        sage: v.display() # expansion w.r.t. the default basis (e)
        e_0 + e_1 + e_2
        sage: v.display(f)
        -f_0 + f_1

    The test suite of the category of modules is passed::

        sage: TestSuite(M).run()

    Constructing an element of ``M`` from (the integer) 0 yields
    the zero element of ``M``::

        sage: M(0)
        Element zero of the Rank-3 free module M over the Integer Ring
        sage: M(0) is M.zero()
        True

    Non-zero elements are constructed by providing their components in
    a given basis::

        sage: v = M([-1,0,3]) ; v  # components in the default basis (e)
        Element of the Rank-3 free module M over the Integer Ring
        sage: v.display() # expansion w.r.t. the default basis (e)
        -e_0 + 3 e_2
        sage: v.display(f)
        f_0 - 6 f_1 + 3 f_2
        sage: v = M([-1,0,3], basis=f) ; v  # components in a specific basis
        Element of the Rank-3 free module M over the Integer Ring
        sage: v.display(f)
        -f_0 + 3 f_2
        sage: v.display()
        e_0 + 6 e_1 + 9 e_2
        sage: v = M([-1,0,3], basis=f, name='v') ; v
        Element v of the Rank-3 free module M over the Integer Ring
        sage: v.display(f)
        v = -f_0 + 3 f_2
        sage: v.display()
        v = e_0 + 6 e_1 + 9 e_2

    An alternative is to construct the element from an empty list of
    componentsand to set the nonzero components afterwards::

        sage: v = M([], name='v')
        sage: v[e,0] = -1
        sage: v[e,2] = 3
        sage: v.display(e)
        v = -e_0 + 3 e_2

    Indices on the free module, such as indices labelling the element of a
    basis, are provided by the generator method :meth:`irange`. By default,
    they range from 0 to the module's rank minus one::

        sage: list(M.irange())
        [0, 1, 2]

    This can be changed via the parameter ``start_index`` in the module
    construction::

        sage: M1 = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
        sage: list(M1.irange())
        [1, 2, 3]

    The parameter ``output_formatter`` in the constructor of the free module
    is used to set the output format of tensor components::

        sage: N = FiniteRankFreeModule(QQ, 3, output_formatter=Rational.numerical_approx)
        sage: e = N.basis('e')
        sage: v = N([1/3, 0, -2], basis=e)
        sage: v[e,:]
        [0.333333333333333, 0.000000000000000, -2.00000000000000]
        sage: v.display(e)  # default format (53 bits of precision)
        0.333333333333333 e_0 - 2.00000000000000 e_2
        sage: v.display(e, format_spec=10)  # 10 bits of precision
        0.33 e_0 - 2.0 e_2
    """

    Element = FiniteRankFreeModuleElement
    _sindex: int

    @staticmethod
    def __classcall_private__(cls, ring, rank, name=None, latex_name=None, start_index=0,
                              output_formatter=None, category=None, ambient=None):
        r"""
        Normalize init arguments for ``UniqueRepresentation``.

        TESTS::

            sage: FiniteRankFreeModule(QQ, 3) is FiniteRankFreeModule(QQ, 3, name=None)
            True
            sage: FiniteRankFreeModule(QQ, 3, name='M') is FiniteRankFreeModule(QQ, 3, name='M', latex_name='M')
            True
            sage: FiniteRankFreeModule(QQ, 3) is FiniteRankFreeModule(QQ, 3, start_index=0)
            True
            sage: FiniteRankFreeModule(QQ, 3) is FiniteRankFreeModule(QQ, 3, output_formatter=None)
            True
            sage: FiniteRankFreeModule(QQ, 3) is FiniteRankFreeModule(QQ, 3, category=Modules(QQ).FiniteDimensional())
            True
        """
        if ring not in Rings().Commutative():
            raise TypeError("the module base ring must be commutative")
        category = Modules(ring).FiniteDimensional().or_subcategory(category)
        if latex_name is None:
            latex_name = name
        return super().__classcall__(
            cls, ring, rank, name, latex_name, start_index, output_formatter, category, ambient)

    def __init__(
        self,
        ring,
        rank,
        name=None,
        latex_name=None,
        start_index: int = 0,
        output_formatter=None,
        category=None,
        ambient=None,
    ):
        r"""
        See :class:`FiniteRankFreeModule` for documentation and examples.

        TESTS::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: TestSuite(M).run()
            sage: e = M.basis('e')
            sage: TestSuite(M).run()
            sage: f = M.basis('f')
            sage: TestSuite(M).run()
        """
        super().__init__(ring, rank, name=name, latex_name=latex_name,
                         category=category, ambient=ambient)
        self._sindex = start_index
        self._output_formatter = output_formatter
        # Dictionary of the tensor modules built on self
        #   (keys = (k,l) --the tensor type)
        # This dictionary is to be extended on need by the method tensor_module
        self._tensor_modules = {}
        # Dictionaries of exterior powers of self and of its dual
        #   (keys = p --the power degree)
        # These dictionaries are to be extended on need by the methods
        # exterior_power and dual_exterior_power
        self._exterior_powers = {}
        self._dual_exterior_powers = {}
        # Set of all modules (tensor powers, exterior powers)
        # that depend on self's bases:
        self._all_modules = {self}
        # List of known bases on the free module:
        self._known_bases = []
        self._def_basis = None # default basis
        self._basis_changes = {} # Dictionary of the changes of bases
        # Identity automorphism:
        self._identity_map = None # to be set by self.identity_map()
        # General linear group:
        self._general_linear_group = None # to be set by
                                          # self.general_linear_group()

    def construction(self):
        """
        The construction functor and base ring for ``self``.

        EXAMPLES::

            sage: FiniteRankFreeModule._clear_cache_() # for doctests only
            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M.construction()
            (VectorFunctor, Integer Ring)
            sage: N = FiniteRankFreeModule(ZZ, 3, name='N', start_index=17)
            sage: N.construction()
            (VectorFunctor, Integer Ring)
        """
        # Try to take it from the category
        c = super().construction()
        if c is not None:
            return c
        # Implementation restrictions:
        if self._output_formatter:
            return None
        from sage.categories.pushout import VectorFunctor
        kwds = dict(is_sparse=False,
                    inner_product_matrix=None,
                    with_basis=None,
                    name_mapping={self.base_ring(): self._name} if self._name else None,
                    latex_name_mapping={self.base_ring(): self._latex_name} if self._latex_name else None)
        if self._sindex:
            return (VectorFunctor(basis_keys=list(self.irange()), **kwds),
                    self.base_ring())
        return (VectorFunctor(n=self.rank(), **kwds),
                self.base_ring())

    #### Parent methods

    def _element_constructor_(self, comp=[], basis=None, name=None,
                              latex_name=None):
        r"""
        Construct an element of ``self``.

        EXAMPLES::

            sage: FiniteRankFreeModule._clear_cache_() # for doctests only
            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: v = M._element_constructor_(comp=[1,0,-2], basis=e, name='v') ; v
            Element v of the Rank-3 free module M over the Integer Ring
            sage: v.display()
            v = e_0 - 2 e_2
            sage: v == M([1,0,-2])
            True
            sage: v = M._element_constructor_(0) ; v
            Element zero of the Rank-3 free module M over the Integer Ring
            sage: v = M._element_constructor_() ; v
            Element of the Rank-3 free module M over the Integer Ring
        """
        if isinstance(comp, (int, Integer)) and comp == 0:
            return self.zero()
        resu = self.element_class(self, name=name, latex_name=latex_name)
        if comp:
            resu.set_comp(basis)[:] = comp
        return resu

    def _an_element_(self):
        r"""
        Construct some (unnamed) element of ``self``.

        EXAMPLES::

            sage: FiniteRankFreeModule._clear_cache_() # for doctests only
            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: v = M._an_element_(); v
            Element of the Rank-3 free module M over the Integer Ring
            sage: v.display()
            e_0 + e_1 + e_2
            sage: v == M.an_element()
            True
            sage: v.parent()
            Rank-3 free module M over the Integer Ring
        """
        if self._def_basis is None:
            self.basis('e')
        resu = self.element_class(self)
        resu.set_comp()[:] = [self._ring.an_element() for i in range(self._rank)]
        return resu

    #### End of parent methods

    #### Methods to be redefined by derived classes ####

    def _repr_(self):
        r"""
        Return a string representation of ``self``.

        EXAMPLES::

            sage: FiniteRankFreeModule(ZZ, 3, name='M')
            Rank-3 free module M over the Integer Ring
        """
        if self._ring in Fields():
            description = "{}-dimensional vector space ".format(self._rank)
        else:
            description = "Rank-{} free module ".format(self._rank)
        if self._name is not None:
            description += self._name + " "
        description += "over the {}".format(self._ring)
        return description

    def _Hom_(self, other, category=None):
        r"""
        Construct the set of homomorphisms ``self`` --> ``other``.

        INPUT:

        - ``other`` -- another free module of finite rank over the same ring
          as ``self``
        - ``category`` -- (default: ``None``) not used here (to ensure
          compatibility with generic hook ``_Hom_``)

        OUTPUT:

        - the hom-set Hom(M,N), where M is ``self`` and N is ``other``

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
            sage: H = M._Hom_(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: H = Hom(M,N) ; H  # indirect doctest
            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
        """
        from .free_module_homset import FreeModuleHomset
        return FreeModuleHomset(self, other)

    def tensor_module(self, k, l, *, sym=None, antisym=None):
        r"""
        Return the free module of all tensors of type `(k, l)` defined on
        ``self``.

        INPUT:

        - ``k`` -- nonnegative integer; the contravariant rank, the tensor
          type being `(k, l)`
        - ``l`` -- nonnegative integer; the covariant rank, the tensor type
          being `(k, l)`
        - ``sym`` -- (default: ``None``) a symmetry or a list of symmetries
          among the tensor arguments: each symmetry is described by a tuple
          containing the positions of the involved arguments, with the
          convention ``position = 0`` for the first argument. For instance:

          * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments
          * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd
            arguments and a symmetry between the 2nd, 4th and 5th arguments.

        - ``antisym`` -- (default: ``None``) antisymmetry or list of
          antisymmetries among the arguments, with the same convention
          as for ``sym``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule`
          representing the free module
          `T^{(k,l)}(M)` of type-`(k,l)` tensors on the free module ``self``

        EXAMPLES:

        Tensor modules over a free module over `\ZZ`::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: T = M.tensor_module(1,2) ; T
            Free module of type-(1,2) tensors on the Rank-3 free module M
             over the Integer Ring
            sage: T.an_element()
            Type-(1,2) tensor on the Rank-3 free module M over the Integer Ring

        Tensor modules are unique::

            sage: M.tensor_module(1,2) is T
            True

        The module of type-`(1,0)` tensors is the base module itself::

            sage: M.tensor_module(1,0) is M
            True

        while the module of type-`(0,1)` tensors is the dual of the base module::

            sage: M.tensor_module(0, 1) is M.dual()
            True

        By using the arguments ``sym`` and ``antisym``, submodules of a full tensor
        module can be constructed::

            sage: T = M.tensor_module(4, 4, sym=((0, 1)), antisym=((4, 5))); T
            Free module of type-(4,4) tensors on the Rank-3 free module M over the Integer Ring,
             with symmetry on the index positions (0, 1),
             with antisymmetry on the index positions (4, 5)
            sage: T._name
            'T^{2,3}(M)⊗T^{6,7}(M*)⊗Sym^{0,1}(M)⊗ASym^{4,5}(M*)'
            sage: latex(T)
            T^{\{2,3\}}(M) \otimes T^{\{6,7\}}(M^*) \otimes \mathrm{Sym}^{\{0,1\}}(M) \otimes \mathrm{ASym}^{\{4,5\}}(M^*)

        See :class:`~sage.tensor.modules.tensor_free_module.TensorFreeModule`
        and :class:`~sage.tensor.modules.tensor_free_module.TensorFreeSubmodule_sym`
        for more documentation.

        TESTS::

            sage: M = FiniteRankFreeModule(ZZ, 2)
            sage: M.tensor_module(2, 0, sym=(0,1)) is M.symmetric_power(2)
            True
        """
        from .comp import CompWithSym

        sym, antisym = CompWithSym._canonicalize_sym_antisym(k + l, sym, antisym)
        if sym or antisym:
            key = (k, l, sym, antisym)
        else:
            key = (k, l)
        try:
            return self._tensor_modules[key]
        except KeyError:
            if key == (1, 0):
                T = self
            elif key == (0, 1):
                T = self.dual()
            elif sym or antisym:
                from sage.tensor.modules.tensor_free_submodule import TensorFreeSubmodule_sym
                T = TensorFreeSubmodule_sym(self, (k, l), sym=sym, antisym=antisym)
            else:
                from sage.tensor.modules.tensor_free_module import TensorFreeModule
                T = TensorFreeModule(self, (k, l))
            self._tensor_modules[key] = T
            return T

    def symmetric_power(self, p):
        r"""
        Return the `p`-th symmetric power of ``self``.

        EXAMPLES:

        Symmetric powers of a free `\ZZ`-module of rank 3::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: M.symmetric_power(0)
            Free module of type-(0,0) tensors on the Rank-3 free module M over the Integer Ring
            sage: M.symmetric_power(1)  # return the module itself
            Rank-3 free module M over the Integer Ring
            sage: M.symmetric_power(1) is M
            True
            sage: M.symmetric_power(2)
            Free module of fully symmetric type-(2,0) tensors
             on the Rank-3 free module M over the Integer Ring
            sage: M.symmetric_power(2).an_element()
            Type-(2,0) tensor on the Rank-3 free module M over the Integer Ring
            sage: M.symmetric_power(2).an_element().display()
            e_0⊗e_0
            sage: M.symmetric_power(3)
            Free module of fully symmetric type-(3,0) tensors
             on the Rank-3 free module M over the Integer Ring
            sage: M.symmetric_power(3).an_element()
            Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring
            sage: M.symmetric_power(3).an_element().display()
            e_0⊗e_0⊗e_0
        """
        if p <= 1:
            return self.tensor_module(p, 0)
        return self.tensor_module(p, 0, sym=(tuple(range(p)),))

    def dual_symmetric_power(self, p):
        r"""
        Return the `p`-th symmetric power of the dual of ``self``.

        EXAMPLES:

        Symmetric powers of the dual of a free `\ZZ`-module of rank 3::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: M.dual_symmetric_power(0)
            Free module of type-(0,0) tensors on the Rank-3 free module M over the Integer Ring
            sage: M.dual_symmetric_power(1)  # return the dual module
            Dual of the Rank-3 free module M over the Integer Ring
            sage: M.dual_symmetric_power(2)
            Free module of fully symmetric type-(0,2) tensors
             on the Rank-3 free module M over the Integer Ring
            sage: M.dual_symmetric_power(2).an_element()
            Symmetric bilinear form  on the Rank-3 free module M over the Integer Ring
            sage: M.dual_symmetric_power(2).an_element().display()
            e^0⊗e^0
            sage: M.dual_symmetric_power(3)
            Free module of fully symmetric type-(0,3) tensors
             on the Rank-3 free module M over the Integer Ring
            sage: M.dual_symmetric_power(3).an_element()
            Type-(0,3) tensor on the Rank-3 free module M over the Integer Ring
            sage: M.dual_symmetric_power(3).an_element().display()
            e^0⊗e^0⊗e^0
        """
        if p <= 1:
            return self.tensor_module(0, p)
        return self.tensor_module(0, p, sym=(tuple(range(p)),))

    def exterior_power(self, p):
        r"""
        Return the `p`-th exterior power of ``self``.

        If `M` stands for the free module ``self``, the *p-th exterior
        power of* `M` is the set `\Lambda^p(M)` of all *alternating
        contravariant tensors* of rank `p`, i.e. of all multilinear maps

        .. MATH::

            \underbrace{M^*\times\cdots\times M^*}_{p\ \; \mbox{times}}
            \longrightarrow R

        that vanish whenever any of two of their arguments are equal.
        `\Lambda^p(M)` is a free module of rank `\binom{n}{p}`
        over the same ring as `M`, where `n` is the rank of `M`.

        INPUT:

        - ``p`` -- nonnegative integer

        OUTPUT:

        - for `p=0`, the base ring `R`
        - for `p=1`, the free module `M`, since `\Lambda^1(M)=M`
        - for `p\geq 2`, instance of
          :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`
          representing the free module `\Lambda^p(M)`

        EXAMPLES:

        Exterior powers of a free `\ZZ`-module of rank 3::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: M.exterior_power(0)  # return the base ring
            Integer Ring
            sage: M.exterior_power(1)  # return the module itself
            Rank-3 free module M over the Integer Ring
            sage: M.exterior_power(1) is M
            True
            sage: M.exterior_power(2)
            2nd exterior power of the Rank-3 free module M over the Integer Ring
            sage: M.exterior_power(2).an_element()
            Alternating contravariant tensor of degree 2 on the Rank-3
             free module M over the Integer Ring
            sage: M.exterior_power(2).an_element().display()
            e_0∧e_1
            sage: M.exterior_power(3)
            3rd exterior power of the Rank-3 free module M over the Integer Ring
            sage: M.exterior_power(3).an_element()
            Alternating contravariant tensor of degree 3 on the Rank-3
             free module M over the Integer Ring
            sage: M.exterior_power(3).an_element().display()
            e_0∧e_1∧e_2

        See
        :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerFreeModule`
        for more documentation.
        """
        try:
            return self._exterior_powers[p]
        except KeyError:
            if p == 0:
                L = self._ring
            elif p == 1:
                L = self
            else:
                from sage.tensor.modules.ext_pow_free_module import ExtPowerFreeModule
                L = ExtPowerFreeModule(self, p)
            self._exterior_powers[p] = L
            return L

    def dual_exterior_power(self, p):
        r"""
        Return the `p`-th exterior power of the dual of ``self``.

        If `M` stands for the free module ``self``, the *p-th exterior
        power of the dual of* `M` is the set `\Lambda^p(M^*)` of all
        *alternating forms of degree* `p` on `M`, i.e. of all
        multilinear maps

        .. MATH::

            \underbrace{M\times\cdots\times M}_{p\ \; \mbox{times}}
            \longrightarrow R

        that vanish whenever any of two of their arguments are equal.
        `\Lambda^p(M^*)` is a free module of rank `\binom{n}{p}`
        over the same ring as `M`, where `n` is the rank of `M`.

        INPUT:

        - ``p`` -- nonnegative integer

        OUTPUT:

        - for `p=0`, the base ring `R`
        - for `p=1`, instance of
          :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankDualFreeModule`
          representing the dual `M^*`
        - for `p\geq 1`, instance of
          :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`
          representing the free module `\Lambda^p(M^*)`

        EXAMPLES:

        Exterior powers of the dual of a free `\ZZ`-module of rank 3::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: M.dual_exterior_power(0)  # return the base ring
            Integer Ring
            sage: M.dual_exterior_power(1)  # return the dual module
            Dual of the Rank-3 free module M over the Integer Ring
            sage: M.dual_exterior_power(1) is M.dual()
            True
            sage: M.dual_exterior_power(2)
            2nd exterior power of the dual of the Rank-3 free module M over the Integer Ring
            sage: M.dual_exterior_power(2).an_element()
            Alternating form of degree 2 on the Rank-3 free module M over the Integer Ring
            sage: M.dual_exterior_power(2).an_element().display()
            e^0∧e^1
            sage: M.dual_exterior_power(3)
            3rd exterior power of the dual of the Rank-3 free module M over the Integer Ring
            sage: M.dual_exterior_power(3).an_element()
            Alternating form of degree 3 on the Rank-3 free module M over the Integer Ring
            sage: M.dual_exterior_power(3).an_element().display()
            e^0∧e^1∧e^2

        See
        :class:`~sage.tensor.modules.ext_pow_free_module.ExtPowerDualFreeModule`
        for more documentation.
        """
        try:
            return self._dual_exterior_powers[p]
        except KeyError:
            if p == 0:
                L = self._ring
            elif p == 1:
                L = FiniteRankDualFreeModule(self)
            else:
                from sage.tensor.modules.ext_pow_free_module import ExtPowerDualFreeModule
                L = ExtPowerDualFreeModule(self, p)
            self._dual_exterior_powers[p] = L
            return L

    def general_linear_group(self):
        r"""
        Return the general linear group of ``self``.

        If ``self`` is the free module `M`, the *general linear group* is the
        group `\mathrm{GL}(M)` of automorphisms of `M`.

        OUTPUT:

        - instance of class
          :class:`~sage.tensor.modules.free_module_linear_group.FreeModuleLinearGroup`
          representing `\mathrm{GL}(M)`

        EXAMPLES:

        The general linear group of a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: GL = M.general_linear_group() ; GL
            General linear group of the Rank-3 free module M over the Integer Ring
            sage: GL.category()
            Category of groups
            sage: type(GL)
            <class 'sage.tensor.modules.free_module_linear_group.FreeModuleLinearGroup_with_category'>

        There is a unique instance of the general linear group::

            sage: M.general_linear_group() is GL
            True

        The group identity element::

            sage: GL.one()
            Identity map of the Rank-3 free module M over the Integer Ring
            sage: GL.one().matrix(e)
            [1 0 0]
            [0 1 0]
            [0 0 1]

        An element::

            sage: GL.an_element()
            Automorphism of the Rank-3 free module M over the Integer Ring
            sage: GL.an_element().matrix(e)
            [ 1  0  0]
            [ 0 -1  0]
            [ 0  0  1]

        See
        :class:`~sage.tensor.modules.free_module_linear_group.FreeModuleLinearGroup`
        for more documentation.
        """
        from sage.tensor.modules.free_module_linear_group import \
                                                          FreeModuleLinearGroup
        if self._general_linear_group is None:
            self._general_linear_group = FreeModuleLinearGroup(self)
        return self._general_linear_group

    def basis(self, symbol, latex_symbol=None, from_family=None,
              indices=None, latex_indices=None, symbol_dual=None,
              latex_symbol_dual=None):
        r"""
        Define or return a basis of the free module ``self``.

        Let `M` denotes the free module ``self`` and `n` its rank.

        The basis can be defined from a set of `n` linearly independent
        elements of `M` by means of the argument ``from_family``.
        If ``from_family`` is not specified, the basis is created from
        scratch and, at this stage, is unrelated to bases that could have been
        defined previously on `M`. It can be related afterwards by means of
        the method :meth:`set_change_of_basis`.

        If the basis specified by the given symbol already exists, it is
        simply returned, whatever the value of the arguments ``latex_symbol``
        or ``from_family``.

        Note that another way to construct a basis of ``self`` is to use
        the method
        :meth:`~sage.tensor.modules.free_module_basis.FreeModuleBasis.new_basis`
        on an existing basis, with the automorphism relating the two bases as
        an argument.

        INPUT:

        - ``symbol`` -- either a string, to be used as a common base for the
          symbols of the elements of the basis, or a list/tuple of strings,
          representing the individual symbols of the elements of the basis
        - ``latex_symbol`` -- (default: ``None``) either a string, to be used
          as a common base for the LaTeX symbols of the elements of the basis,
          or a list/tuple of strings, representing the individual LaTeX symbols
          of the elements of the basis; if ``None``, ``symbol`` is used in
          place of ``latex_symbol``
        - ``from_family`` -- (default: ``None``) tuple or list of `n` linearly
          independent elements of the free module ``self`` (`n` being the
          rank of ``self``)
        - ``indices`` -- (default: ``None``; used only if ``symbol`` is a
          single string) list/tuple of strings representing the indices
          labelling the elements of the basis; if ``None``, the indices will be
          generated as integers within the range declared on ``self``
        - ``latex_indices`` -- (default: ``None``) list/tuple of strings
          representing the indices for the LaTeX symbols of the elements of
          the basis; if ``None``, ``indices`` is used instead
        - ``symbol_dual`` -- (default: ``None``) same as ``symbol`` but for the
          dual basis; if ``None``, ``symbol`` must be a string and is used
          for the common base of the symbols of the elements of the dual basis
        - ``latex_symbol_dual`` -- (default: ``None``) same as ``latex_symbol``
          but for the dual basis

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`
          representing a basis on ``self``

        EXAMPLES:

        Bases on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e') ; e
            Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
            sage: e[0]
            Element e_0 of the Rank-3 free module M over the Integer Ring
            sage: latex(e)
            \left(e_{0},e_{1},e_{2}\right)

        The LaTeX symbol can be set explicitly::

            sage: eps = M.basis('eps', latex_symbol=r'\epsilon') ; eps
            Basis (eps_0,eps_1,eps_2) on the Rank-3 free module M
             over the Integer Ring
            sage: latex(eps)
            \left(\epsilon_{0},\epsilon_{1},\epsilon_{2}\right)

        The indices can be customized::

            sage: f = M.basis('f', indices=('x', 'y', 'z')); f
            Basis (f_x,f_y,f_z) on the Rank-3 free module M over the Integer Ring
            sage: latex(f[1])
            f_{y}

        By providing a list or a tuple for the argument ``symbol``, one can
        have a different symbol for each element of the basis; it is then
        mandatory to specify some symbols for the dual basis::

            sage: g = M.basis(('a', 'b', 'c'), symbol_dual=('A', 'B', 'C')); g
            Basis (a,b,c) on the Rank-3 free module M over the Integer Ring
            sage: g.dual_basis()
            Dual basis (A,B,C) on the Rank-3 free module M over the Integer Ring

        If the provided symbol and indices are that of an already defined
        basis, the latter is returned (no new basis is created)::

            sage: M.basis('e') is e
            True
            sage: M.basis('eps') is eps
            True
            sage: M.basis('e', indices=['x', 'y', 'z']) is e
            False
            sage: M.basis('e', indices=['x', 'y', 'z']) is \
            ....:  M.basis('e', indices=['x', 'y', 'z'])
            True

        The individual elements of the basis are labelled according the
        parameter ``start_index`` provided at the free module construction::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
            sage: e = M.basis('e') ; e
            Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
            sage: e[1]
            Element e_1 of the Rank-3 free module M over the Integer Ring

        Construction of a basis from a spanning family of linearly independent
        module elements::

            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: f[1].display()
            f_1 = -e_2
            sage: f[2].display()
            f_2 = 4 e_1 + 3 e_3
            sage: f[3].display()
            f_3 = 7 e_1 + 5 e_3

        The change-of-basis automorphisms have been registered::

            sage: M.change_of_basis(e,f).matrix(e)
            [ 0  4  7]
            [-1  0  0]
            [ 0  3  5]
            sage: M.change_of_basis(f,e).matrix(e)
            [ 0 -1  0]
            [-5  0  7]
            [ 3  0 -4]
            sage: M.change_of_basis(f,e) == M.change_of_basis(e,f).inverse()
            True

        Check of the change-of-basis e --> f::

            sage: a = M.change_of_basis(e,f) ; a
            Automorphism of the Rank-3 free module M over the Integer Ring
            sage: all( f[i] == a(e[i]) for i in M.irange() )
            True

        Providing a family of module elements that are not linearly independent
        raise an error::

            sage: g = M.basis('g', from_family=(f1, f2, f1+f2))
            Traceback (most recent call last):
            ...
            ValueError: the provided module elements are not linearly
             independent

        For more documentation on bases see
        :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`.
        """
        from .free_module_basis import FreeModuleBasis
        for other in self._known_bases:
            if symbol == other._symbol and indices == other._indices:
                return other
        resu = FreeModuleBasis(self, symbol, latex_symbol=latex_symbol,
                               indices=indices, latex_indices=latex_indices,
                               symbol_dual=symbol_dual,
                               latex_symbol_dual=latex_symbol_dual)
        if from_family:
            try:
                resu._init_from_family(from_family)
            except ZeroDivisionError:
                raise ValueError("the provided module elements are not "
                                 "linearly independent")
        return resu

    def _test_basis(self, tester=None, **options):
        r"""
        Test that the ``basis`` method works correctly.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M._test_basis(verbose=True)
            <BLANKLINE>
              Running the test suite of self.basis('test')
              running ._test_an_element() . . . pass
              running ._test_cardinality() . . . pass
              running ._test_category() . . . pass
              running ._test_construction() . . . pass
              running ._test_elements() . . .
              Running the test suite of self.an_element()
                running ._test_category() . . . pass
                running ._test_eq() . . . pass
                running ._test_new() . . . pass
                running ._test_nonzero_equal() . . . pass
                running ._test_not_implemented_methods() . . . pass
                running ._test_pickling() . . . pass
                pass
              running ._test_elements_eq_reflexive() . . . pass
              running ._test_elements_eq_symmetric() . . . pass
              running ._test_elements_eq_transitive() . . . pass
              running ._test_elements_neq() . . . pass
              running ._test_enumerated_set_contains() . . . pass
              running ._test_enumerated_set_iter_cardinality() . . . pass
              running ._test_enumerated_set_iter_list() . . . pass
              running ._test_eq() . . . pass
              running ._test_iter_len() . . . pass
              running ._test_new() . . . pass
              running ._test_not_implemented_methods() . . . pass
              running ._test_pickling() . . . pass
              running ._test_random() . . . pass
              running ._test_rank() . . . pass
              running ._test_some_elements() . . . pass
        """
        from sage.misc.sage_unittest import TestSuite
        # The intention is to raise an exception only if this is
        # run as a sub-testsuite of a larger testsuite.
        # (from _test_elements)
        is_sub_testsuite = (tester is not None)
        tester = self._tester(tester=tester, **options)
        try:
            b = self.basis('test')
        except NotImplementedError:
            return
        # Test uniqueness
        b_again = self.basis('test')
        tester.assertTrue(b is b_again)
        # Test rank
        tester.assertEqual(len(b), self.rank())
        indices = list(self.irange())
        tester.assertEqual(len(b), len(indices))
        # Test basis indexing
        for index, element in zip(indices, b):
            tester.assertTrue(element is b[index])
        # Run test suite of the basis object (similar to _test_elements)
        tester.info("\n  Running the test suite of self.basis('test')")
        TestSuite(b).run(verbose=tester._verbose, prefix=tester._prefix + "  ",
                         raise_on_failure=is_sub_testsuite)

    def _tensor(self, tensor_type, name=None, latex_name=None, sym=None,
               antisym=None):
        r"""
        Construct a tensor on the free module ``self``.

        INPUT:

        - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the
          contravariant rank and ``l`` the covariant rank

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

        - ``latex_name`` -- (default: ``None``) string;  LaTeX symbol to
          denote the tensor; if none is provided, the LaTeX symbol is set
          to ``name``

        - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries
          among the tensor arguments: each symmetry is described by a tuple
          containing the positions of the involved arguments, with the
          convention ``position = 0`` for the first argument. For instance:

          * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments
          * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd
            arguments and a symmetry between the 2nd, 4th and 5th arguments.

        - ``antisym`` -- (default: ``None``) antisymmetry or iterable of
          antisymmetries among the arguments, with the same convention
          as for ``sym``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
          representing the tensor defined on ``self`` with the provided
          characteristics

        EXAMPLES:

        Tensors on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: t = M._tensor((1,0), name='t') ; t
            Element t of the Rank-3 free module M over the Integer Ring
        """
        from .comp import CompWithSym
        sym, antisym = CompWithSym._canonicalize_sym_antisym(
            tensor_type[0] + tensor_type[1], sym, antisym)
        # Special cases:
        if tensor_type == (1,0):
            return self.element_class(self, name=name, latex_name=latex_name)
        if tensor_type == (0,1):
            return self.linear_form(name=name, latex_name=latex_name)
        if tensor_type[0] == 0 and tensor_type[1] > 1 and antisym:
            if len(antisym[0]) == tensor_type[1]:
                return self.alternating_form(tensor_type[1], name=name,
                                             latex_name=latex_name)
        elif tensor_type[0] > 1 and tensor_type[1] == 0 and antisym:
            if len(antisym[0]) == tensor_type[0]:
                return self.alternating_contravariant_tensor(tensor_type[0],
                                           name=name, latex_name=latex_name)
        # Generic case:
        return self.tensor_module(*tensor_type).element_class(self,
                                 tensor_type, name=name, latex_name=latex_name,
                                 sym=sym, antisym=antisym)

    def tensor(self, *args, **kwds):
        r"""
        Construct a tensor on the free module ``self`` or a tensor product with other modules.

        If ``args`` consist of other parents, just delegate to :meth:`tensor_product`.

        Otherwise, construct a tensor from the following input.

        INPUT:

        - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the
          contravariant rank and ``l`` the covariant rank

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

        - ``latex_name`` -- (default: ``None``) string;  LaTeX symbol to
          denote the tensor; if none is provided, the LaTeX symbol is set
          to ``name``

        - ``sym`` -- (default: ``None``) a symmetry or an iterable of symmetries
          among the tensor arguments: each symmetry is described by a tuple
          containing the positions of the involved arguments, with the
          convention ``position = 0`` for the first argument. For instance:

          * ``sym = (0,1)`` for a symmetry between the 1st and 2nd arguments
          * ``sym = [(0,2), (1,3,4)]`` for a symmetry between the 1st and 3rd
            arguments and a symmetry between the 2nd, 4th and 5th arguments.

        - ``antisym`` -- (default: ``None``) antisymmetry or iterable of
          antisymmetries among the arguments, with the same convention
          as for ``sym``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
          representing the tensor defined on ``self`` with the provided
          characteristics

        EXAMPLES:

        Tensors on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: t = M.tensor((1,0), name='t') ; t
            Element t of the Rank-3 free module M over the Integer Ring
            sage: t = M.tensor((0,1), name='t') ; t
            Linear form t on the Rank-3 free module M over the Integer Ring
            sage: t = M.tensor((1,1), name='t') ; t
            Type-(1,1) tensor t on the Rank-3 free module M over the Integer Ring
            sage: t = M.tensor((0,2), name='t', sym=(0,1)) ; t
            Symmetric bilinear form t on the
             Rank-3 free module M over the Integer Ring
            sage: t = M.tensor((0,2), name='t', antisym=(0,1)) ; t
            Alternating form t of degree 2 on the
             Rank-3 free module M over the Integer Ring
            sage: t = M.tensor((1,2), name='t') ; t
            Type-(1,2) tensor t on the Rank-3 free module M over the Integer Ring

        See :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
        for more examples and documentation.

        TESTS:

        Trivial symmetries in the list of symmetries or antisymmetries are silently
        ignored::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M.tensor((3,0), sym=[[1]])
            Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring
            sage: M.tensor((3,0), antisym=[[]])
            Type-(3,0) tensor on the Rank-3 free module M over the Integer Ring
        """
        # Until https://github.com/sagemath/sage/issues/30373 is done,
        # TensorProductFunctor._functor_name is "tensor", so this method
        # also needs to double as the tensor product construction
        if isinstance(args[0], Parent):
            return self.tensor_product(*args, **kwds)
        return self._tensor(*args, **kwds)

    def tensor_from_comp(self, tensor_type, comp, name=None, latex_name=None):
        r"""
        Construct a tensor on ``self`` from a set of components.

        The tensor symmetries are deduced from those of the components.

        INPUT:

        - ``tensor_type`` -- pair ``(k, l)`` with ``k`` being the
          contravariant rank and ``l`` the covariant rank
        - ``comp`` -- instance of :class:`~sage.tensor.modules.comp.Components`
          representing the tensor components in a given basis
        - ``name`` -- (default: ``None``) string; name given to the tensor
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
          the tensor; if none is provided, the LaTeX symbol is set to ``name``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
          representing the tensor defined on ``self`` with the provided
          characteristics.

        EXAMPLES:

        Construction of a tensor of rank 1::

            sage: from sage.tensor.modules.comp import Components, CompWithSym, CompFullySym, CompFullyAntiSym
            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e') ; e
            Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
            sage: c = Components(ZZ, e, 1)
            sage: c[:]
            [0, 0, 0]
            sage: c[:] = [-1,4,2]
            sage: t = M.tensor_from_comp((1,0), c)
            sage: t
            Element of the Rank-3 free module M over the Integer Ring
            sage: t.display(e)
            -e_0 + 4 e_1 + 2 e_2
            sage: t = M.tensor_from_comp((0,1), c) ; t
            Linear form on the Rank-3 free module M over the Integer Ring
            sage: t.display(e)
            -e^0 + 4 e^1 + 2 e^2

        Construction of a tensor of rank 2::

            sage: c = CompFullySym(ZZ, e, 2)
            sage: c[0,0], c[1,2] = 4, 5
            sage: t = M.tensor_from_comp((0,2), c) ; t
            Symmetric bilinear form on the
             Rank-3 free module M over the Integer Ring
            sage: t.symmetries()
            symmetry: (0, 1);  no antisymmetry
            sage: t.display(e)
            4 e^0⊗e^0 + 5 e^1⊗e^2 + 5 e^2⊗e^1
            sage: c = CompFullyAntiSym(ZZ, e, 2)
            sage: c[0,1], c[1,2] = 4, 5
            sage: t = M.tensor_from_comp((0,2), c) ; t
            Alternating form of degree 2 on the
             Rank-3 free module M over the Integer Ring
            sage: t.display(e)
            4 e^0∧e^1 + 5 e^1∧e^2
        """
        from .comp import CompWithSym, CompFullyAntiSym

        # 0/ Compatibility checks:
        if comp._ring is not self._ring:
            raise TypeError("the components are not defined on the same"
                            " ring as the module")
        if comp._frame not in self._known_bases:
            raise TypeError("the components are not defined on a basis of"
                            " the module")
        if comp._nid != tensor_type[0] + tensor_type[1]:
            raise TypeError("number of component indices not compatible with "
                            " the tensor type")

        # 1/ Construction of the tensor:
        if tensor_type == (1, 0):
            resu = self.element_class(self, name=name, latex_name=latex_name)
        elif tensor_type == (0, 1):
            resu = self.linear_form(name=name, latex_name=latex_name)
        elif tensor_type[0] == 0 and tensor_type[1] > 1 and \
                                        isinstance(comp, CompFullyAntiSym):
            resu = self.alternating_form(tensor_type[1], name=name,
                                         latex_name=latex_name)
        elif tensor_type[0] > 1 and tensor_type[1] == 0 and \
                                        isinstance(comp, CompFullyAntiSym):
            resu = self.alternating_contravariant_tensor(tensor_type[0],
                                         name=name,
                                         latex_name=latex_name)
        else:
            resu = self.tensor_module(*tensor_type).element_class(self,
                                 tensor_type, name=name, latex_name=latex_name)
            # Tensor symmetries deduced from those of comp:
            if isinstance(comp, CompWithSym):
                resu._sym = comp._sym
                resu._antisym = comp._antisym

        # 2/ Tensor components set to comp:
        resu._components[comp._frame] = comp

        return resu

    def alternating_contravariant_tensor(self, degree, name=None,
                                         latex_name=None):
        r"""
        Construct an alternating contravariant tensor on the free module.

        INPUT:

        - ``degree`` -- degree of the alternating contravariant tensor
          (i.e. its tensor rank)
        - ``name`` -- (default: ``None``) string; name given to the
          alternating contravariant tensor
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
          denote the alternating contravariant tensor; if none is
          provided, the LaTeX symbol is set to ``name``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor`

        EXAMPLES:

        Alternating contravariant tensor on a rank-3 module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: a = M.alternating_contravariant_tensor(2, 'a') ; a
            Alternating contravariant tensor a of degree 2 on the
             Rank-3 free module M over the Integer Ring

        The nonzero components in a given basis have to be set in a second
        step, thereby fully specifying the alternating form::

            sage: e = M.basis('e') ; e
            Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
            sage: a.set_comp(e)[0,1] = 2
            sage: a.set_comp(e)[1,2] = -3
            sage: a.display(e)
            a = 2 e_0∧e_1 - 3 e_1∧e_2

        An alternating contravariant tensor of degree 1 is simply
        an element of the module::

            sage: a = M.alternating_contravariant_tensor(1, 'a') ; a
            Element a of the Rank-3 free module M over the Integer Ring

        See
        :class:`~sage.tensor.modules.alternating_contr_tensor.AlternatingContrTensor`
        for more documentation.
        """
        if degree == 1:
            return self.element_class(self, name=name,
                                      latex_name=latex_name)
        return self.exterior_power(degree).element_class(self, degree,
                                       name=name, latex_name=latex_name)

    def alternating_form(self, degree, name=None, latex_name=None):
        r"""
        Construct an alternating form on the free module.

        INPUT:

        - ``degree`` -- the degree of the alternating form (i.e. its
          tensor rank)
        - ``name`` -- (default: ``None``) string; name given to the
          alternating form
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
          denote the alternating form; if none is provided, the LaTeX symbol
          is set to ``name``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`

        EXAMPLES:

        Alternating forms on a rank-3 module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: a = M.alternating_form(2, 'a') ; a
            Alternating form a of degree 2 on the
             Rank-3 free module M over the Integer Ring

        The nonzero components in a given basis have to be set in a second
        step, thereby fully specifying the alternating form::

            sage: e = M.basis('e') ; e
            Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
            sage: a.set_comp(e)[0,1] = 2
            sage: a.set_comp(e)[1,2] = -3
            sage: a.display(e)
            a = 2 e^0∧e^1 - 3 e^1∧e^2

        An alternating form of degree 1 is a linear form::

            sage: a = M.alternating_form(1, 'a') ; a
            Linear form a on the Rank-3 free module M over the Integer Ring

        To construct such a form, it is preferable to call the method
        :meth:`linear_form` instead::

            sage: a = M.linear_form('a') ; a
            Linear form a on the Rank-3 free module M over the Integer Ring

        See
        :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`
        for more documentation.
        """
        if degree == 0:
            try:
                return self._ring.element_class(self._ring, name=name,
                                                latex_name=latex_name)
            except (KeyError, AttributeError):
                raise NotImplementedError('{} apparently '.format(self._ring) +
                                          'does not provide generic elements')
        return self.dual_exterior_power(degree).element_class(self, degree,
                                              name=name, latex_name=latex_name)

    def linear_form(self, name=None, latex_name=None):
        r"""
        Construct a linear form on the free module ``self``.

        A *linear form* on a free module `M` over a ring `R` is a map
        `M \rightarrow R` that is linear. It can be viewed as a tensor of type
        `(0,1)` on `M`.

        INPUT:

        - ``name`` -- (default: ``None``) string; name given to the linear
          form
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
          denote the linear form; if none is provided, the LaTeX symbol
          is set to ``name``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`

        EXAMPLES:

        Linear form on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: a = M.linear_form('A') ; a
            Linear form A on the Rank-3 free module M over the Integer Ring
            sage: a[:] = [2,-1,3]  # components w.r.t. the module's default basis (e)
            sage: a.display()
            A = 2 e^0 - e^1 + 3 e^2

        A linear form maps module elements to ring elements::

            sage: v = M([1,1,1])
            sage: a(v)
            4

        Test of linearity::

            sage: u = M([-5,-2,7])
            sage: a(3*u - 4*v) == 3*a(u) - 4*a(v)
            True

        See
        :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`
        for more documentation.
        """
        return self.dual_exterior_power(1).element_class(self, 1, name=name,
                                                         latex_name=latex_name)

    def automorphism(self, matrix=None, basis=None, name=None,
                     latex_name=None):
        r"""
        Construct a module automorphism of ``self``.

        Denoting ``self`` by `M`, an automorphism of ``self`` is an element
        of the general linear group `\mathrm{GL}(M)`.

        INPUT:

        - ``matrix`` -- (default: ``None``) matrix of size rank(M)*rank(M)
          representing the automorphism with respect to ``basis``;
          this entry can actually be any material from which a matrix of
          elements of ``self`` base ring can be constructed; the *columns* of
          ``matrix`` must be the components w.r.t. ``basis`` of
          the images of the elements of ``basis``. If ``matrix`` is ``None``,
          the automorphism has to be initialized afterwards by
          method :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.set_comp`
          or via the operator [].
        - ``basis`` -- (default: ``None``) basis of ``self`` defining the
          matrix representation; if ``None`` the default basis of ``self`` is
          assumed.
        - ``name`` -- (default: ``None``) string; name given to the
          automorphism
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
          denote the automorphism; if none is provided, the LaTeX symbol
          is set to ``name``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`

        EXAMPLES:

        Automorphism of a rank-2 free `\ZZ`-module::

            sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
            sage: e = M.basis('e')
            sage: a = M.automorphism(matrix=[[1,2],[1,3]], basis=e, name='a') ; 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)
            [1 2]
            [1 3]

        An automorphism is a tensor of type (1,1)::

            sage: a.tensor_type()
            (1, 1)
            sage: a.display(e)
            a = e_0⊗e^0 + 2 e_0⊗e^1 + e_1⊗e^0 + 3 e_1⊗e^1

        The automorphism components can be specified in a second step, as
        components of a type-`(1,1)` tensor::

            sage: a1 = M.automorphism(name='a')
            sage: a1[e,:] = [[1,2],[1,3]]
            sage: a1.matrix(e)
            [1 2]
            [1 3]
            sage: a1 == a
            True

        Component by component specification::

            sage: a2 = M.automorphism(name='a')
            sage: a2[0,0] = 1  # component set in the module's default basis (e)
            sage: a2[0,1] = 2
            sage: a2[1,0] = 1
            sage: a2[1,1] = 3
            sage: a2.matrix(e)
            [1 2]
            [1 3]
            sage: a2 == a
            True

        See
        :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`
        for more documentation.
        """
        resu = self.general_linear_group().element_class(self, name=name,
                                                         latex_name=latex_name)
        if matrix:
            if basis is None:
                basis = self.default_basis()
            resu.set_comp(basis)[:] = matrix
        return resu

    def sym_bilinear_form(self, name=None, latex_name=None):
        r"""
        Construct a symmetric bilinear form on the free module ``self``.

        INPUT:

        - ``name`` -- (default: ``None``) string; name given to the symmetric
          bilinear form
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to
          denote the symmetric bilinear form; if none is provided, the LaTeX
          symbol is set to ``name``

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
          of tensor type `(0,2)` and symmetric

        EXAMPLES:

        Symmetric bilinear form on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: a = M.sym_bilinear_form('A') ; a
            Symmetric bilinear form A on the
             Rank-3 free module M over the Integer Ring

        A symmetric bilinear form is a type-`(0,2)` tensor that is symmetric::

            sage: a.parent()
            Free module of type-(0,2) tensors on the
             Rank-3 free module M over the Integer Ring
            sage: a.tensor_type()
            (0, 2)
            sage: a.tensor_rank()
            2
            sage: a.symmetries()
            symmetry: (0, 1);  no antisymmetry

        Components with respect to a given basis::

            sage: e = M.basis('e')
            sage: a[0,0], a[0,1], a[0,2] = 1, 2, 3
            sage: a[1,1], a[1,2] = 4, 5
            sage: a[2,2] = 6

        Only independent components have been set; the other ones are
        deduced by symmetry::

            sage: a[1,0], a[2,0], a[2,1]
            (2, 3, 5)
            sage: a[:]
            [1 2 3]
            [2 4 5]
            [3 5 6]

        A symmetric bilinear form acts on pairs of module elements::

            sage: u = M([2,-1,3]) ; v = M([-2,4,1])
            sage: a(u,v)
            61
            sage: a(v,u) == a(u,v)
            True

        The sum of two symmetric bilinear forms is another symmetric bilinear
        form::

            sage: b = M.sym_bilinear_form('B')
            sage: b[0,0], b[0,1], b[1,2] = -2, 1, -3
            sage: s = a + b ; s
            Symmetric bilinear form A+B on the
             Rank-3 free module M over the Integer Ring
            sage: a[:], b[:], s[:]
            (
            [1 2 3]  [-2  1  0]  [-1  3  3]
            [2 4 5]  [ 1  0 -3]  [ 3  4  2]
            [3 5 6], [ 0 -3  0], [ 3  2  6]
            )

        Adding a symmetric bilinear from with a non-symmetric one results in a
        generic type-`(0,2)` tensor::

            sage: c = M.tensor((0,2), name='C')
            sage: c[0,1] = 4
            sage: s = a + c ; s
            Type-(0,2) tensor A+C on the Rank-3 free module M over the Integer Ring
            sage: s.symmetries()
            no symmetry;  no antisymmetry
            sage: s[:]
            [1 6 3]
            [2 4 5]
            [3 5 6]

        See :class:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor`
        for more documentation.
        """
        return self.tensor_module(0,2).element_class(self, (0,2), name=name,
                                              latex_name=latex_name, sym=(0,1))

    #### End of methods to be redefined by derived classes ####

    def dual(self):
        r"""
        Return the dual module of ``self``.

        EXAMPLES:

        Dual of a free module over `\ZZ`::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: M.dual()
            Dual of the Rank-3 free module M over the Integer Ring
            sage: latex(M.dual())
            M^*

        The dual is a free module of the same rank as M::

            sage: from sage.tensor.modules.finite_rank_free_module import FiniteRankFreeModule_abstract
            sage: isinstance(M.dual(), FiniteRankFreeModule_abstract)
            True
            sage: M.dual().rank()
            3

        It is formed by alternating forms of degree 1, i.e. linear forms::

            sage: M.dual() is M.dual_exterior_power(1)
            True
            sage: M.dual().an_element()
            Linear form on the Rank-3 free module M over the Integer Ring
            sage: a = M.linear_form()
            sage: a in M.dual()
            True

        The elements of a dual basis belong of course to the dual module::

            sage: e = M.basis('e')
            sage: e.dual_basis()[0] in M.dual()
            True
        """
        return self.dual_exterior_power(1)

    def irange(self, start: int | None = None) -> Generator[int, None, None]:
        r"""
        Single index generator, labelling the elements of a basis of ``self``.

        INPUT:

        - ``start`` -- (default: ``None``) integer; initial value of the
          index; if none is provided, ``self._sindex`` is assumed

        OUTPUT:

        - an iterable index, starting from ``start`` and ending at
          ``self._sindex + self.rank() - 1``

        EXAMPLES:

        Index range on a rank-3 module::

            sage: M = FiniteRankFreeModule(ZZ, 3)
            sage: list(M.irange())
            [0, 1, 2]
            sage: list(M.irange(start=1))
            [1, 2]

        The default starting value corresponds to the parameter ``start_index``
        provided at the module construction (the default value being 0)::

            sage: M1 = FiniteRankFreeModule(ZZ, 3, start_index=1)
            sage: list(M1.irange())
            [1, 2, 3]
            sage: M2 = FiniteRankFreeModule(ZZ, 3, start_index=-4)
            sage: list(M2.irange())
            [-4, -3, -2]
        """
        si = self._sindex
        imax = self._rank + si
        if start is None:
            i = si
        else:
            i = start
        while i < imax:
            yield i
            i += 1

    def default_basis(self):
        r"""
        Return the default basis of the free module ``self``.

        The *default basis* is simply a basis whose name can be skipped in
        methods requiring a basis as an argument. By default, it is the first
        basis introduced on the module. It can be changed by the method
        :meth:`set_default_basis`.

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`

        EXAMPLES:

        At the module construction, no default basis is assumed::

            sage: M = FiniteRankFreeModule(ZZ, 2, name='M', start_index=1)
            sage: M.default_basis()
            No default basis has been defined on the
             Rank-2 free module M over the Integer Ring

        The first defined basis becomes the default one::

            sage: e = M.basis('e') ; e
            Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
            sage: M.default_basis()
            Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
            sage: f =  M.basis('f') ; f
            Basis (f_1,f_2) on the Rank-2 free module M over the Integer Ring
            sage: M.default_basis()
            Basis (e_1,e_2) on the Rank-2 free module M over the Integer Ring
        """
        if self._def_basis is None:
            print("No default basis has been defined on the {}".format(self))
        return self._def_basis

    def set_default_basis(self, basis):
        r"""
        Set the default basis of ``self``.

        The *default basis* is simply a basis whose name can be skipped in
        methods requiring a basis as an argument. By default, it is the first
        basis introduced on the module.

        INPUT:

        - ``basis`` -- instance of
          :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`
          representing a basis on ``self``

        EXAMPLES:

        Changing the default basis on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M', start_index=1)
            sage: e = M.basis('e') ; e
            Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
            sage: f =  M.basis('f') ; f
            Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring
            sage: M.default_basis()
            Basis (e_1,e_2,e_3) on the Rank-3 free module M over the Integer Ring
            sage: M.set_default_basis(f)
            sage: M.default_basis()
            Basis (f_1,f_2,f_3) on the Rank-3 free module M over the Integer Ring
        """
        from .free_module_basis import FreeModuleBasis
        if not isinstance(basis, FreeModuleBasis):
            raise TypeError("the argument is not a free module basis")
        if basis._fmodule is not self:
            raise ValueError("the basis is not defined on the current module")
        self._def_basis = basis

    def print_bases(self):
        r"""
        Display the bases that have been defined on the free module ``self``.

        Use the method :meth:`bases` to get the raw list of bases.

        EXAMPLES:

        Bases on a rank-4 free module::

            sage: M = FiniteRankFreeModule(ZZ, 4, name='M', start_index=1)
            sage: M.print_bases()
            No basis has been defined on the
             Rank-4 free module M over the Integer Ring
            sage: e = M.basis('e')
            sage: M.print_bases()
            Bases defined on the Rank-4 free module M over the Integer Ring:
             - (e_1,e_2,e_3,e_4) (default basis)
            sage: f = M.basis('f')
            sage: M.print_bases()
            Bases defined on the Rank-4 free module M over the Integer Ring:
             - (e_1,e_2,e_3,e_4) (default basis)
             - (f_1,f_2,f_3,f_4)
            sage: M.set_default_basis(f)
            sage: M.print_bases()
            Bases defined on the Rank-4 free module M over the Integer Ring:
             - (e_1,e_2,e_3,e_4)
             - (f_1,f_2,f_3,f_4) (default basis)

        """
        if not self._known_bases:
            print("No basis has been defined on the {}".format(self))
        else:
            print("Bases defined on the {}:".format(self))
            for basis in self._known_bases:
                item = " - " + basis._name
                if basis is self._def_basis:
                    item += " (default basis)"
                print(item)

    def bases(self):
        r"""
        Return the list of bases that have been defined on the free module
        ``self``.

        Use the method :meth:`print_bases` to get a formatted output with more
        information.

        OUTPUT:

        - list of instances of class
          :class:`~sage.tensor.modules.free_module_basis.FreeModuleBasis`

        EXAMPLES:

        Bases on a rank-3 free module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M_3', start_index=1)
            sage: M.bases()
            []
            sage: e = M.basis('e')
            sage: M.bases()
            [Basis (e_1,e_2,e_3) on the Rank-3 free module M_3 over the Integer Ring]
            sage: f = M.basis('f')
            sage: M.bases()
            [Basis (e_1,e_2,e_3) on the Rank-3 free module M_3 over the Integer Ring,
             Basis (f_1,f_2,f_3) on the Rank-3 free module M_3 over the Integer Ring]
        """
        return list(self._known_bases)

    def change_of_basis(self, basis1, basis2):
        r"""
        Return a module automorphism linking two bases defined on the free
        module ``self``.

        If the automorphism has not been recorded yet (in the internal
        dictionary ``self._basis_changes``), it is computed by transitivity,
        i.e. by performing products of recorded changes of basis.

        INPUT:

        - ``basis1`` -- a basis of ``self``, denoted `(e_i)` below
        - ``basis2`` -- a basis of ``self``, denoted `(f_i)` below

        OUTPUT:

        - instance of
          :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`
          describing the automorphism `P` that relates the basis `(e_i)` to the
          basis `(f_i)` according to `f_i = P(e_i)`

        EXAMPLES:

        Changes of basis on a rank-2 free module::

            sage: FiniteRankFreeModule._clear_cache_() # for doctests only
            sage: M = FiniteRankFreeModule(ZZ, 2, name='M', start_index=1)
            sage: e = M.basis('e')
            sage: f = M.basis('f', from_family=(e[1]+2*e[2], e[1]+3*e[2]))
            sage: P = M.change_of_basis(e,f) ; P
            Automorphism of the Rank-2 free module M over the Integer Ring
            sage: P.matrix(e)
            [1 1]
            [2 3]

        Note that the columns of this matrix contain the components of the
        elements of basis ``f`` w.r.t. to basis ``e``::

            sage: f[1].display(e)
            f_1 = e_1 + 2 e_2
            sage: f[2].display(e)
            f_2 = e_1 + 3 e_2

        The change of basis is cached::

            sage: P is M.change_of_basis(e,f)
            True

        Check of the change-of-basis automorphism::

            sage: f[1] == P(e[1])
            True
            sage: f[2] == P(e[2])
            True

        Check of the reverse change of basis::

            sage: M.change_of_basis(f,e) == P^(-1)
            True

        We have of course::

            sage: M.change_of_basis(e,e)
            Identity map of the Rank-2 free module M over the Integer Ring
            sage: M.change_of_basis(e,e) is M.identity_map()
            True

        Let us introduce a third basis on ``M``::

            sage: h = M.basis('h', from_family=(3*e[1]+4*e[2], 5*e[1]+7*e[2]))

        The change of basis ``e`` --> ``h`` has been recorded directly from the
        definition of ``h``::

            sage: Q = M.change_of_basis(e,h) ; Q.matrix(e)
            [3 5]
            [4 7]

        The change of basis ``f`` --> ``h`` is computed by transitivity, i.e.
        from the changes of basis ``f`` --> ``e`` and ``e`` --> ``h``::

            sage: R = M.change_of_basis(f,h) ; R
            Automorphism of the Rank-2 free module M over the Integer Ring
            sage: R.matrix(e)
            [-1  2]
            [-2  3]
            sage: R.matrix(f)
            [ 5  8]
            [-2 -3]

        Let us check that ``R`` is indeed the change of basis ``f`` --> ``h``::

            sage: h[1] == R(f[1])
            True
            sage: h[2] == R(f[2])
            True

        A related check is::

            sage: R == Q*P^(-1)
            True
        """
        if basis1 == basis2:
            return self.identity_map()
        bc = self._basis_changes
        if (basis1, basis2) not in bc:
            if basis1 not in self._known_bases:
                raise TypeError("{} is not a basis of the {}".format(basis1,
                                                                     self))
            if basis2 not in self._known_bases:
                raise TypeError("{} is not a basis of the {}".format(basis2,
                                                                     self))
            # Is the inverse already registered ?
            if (basis2, basis1) in bc:
                inv = bc[(basis2, basis1)].inverse()
                bc[(basis1, basis2)] = inv
                return inv
            # Search for a third basis, basis say, such that either the changes
            # basis1 --> basis and basis --> basis2
            # or
            # basis2 --> basis and basis --> basis1
            # are known:
            for basis in self._known_bases:
                if (basis1, basis) in bc and (basis, basis2) in bc:
                    transf = bc[(basis, basis2)] * bc[(basis1, basis)]
                    bc[(basis1, basis2)] = transf
                    bc[(basis2, basis1)] = transf.inverse()
                    break
                if (basis2, basis) in bc and (basis, basis1) in bc:
                    inv = bc[(basis, basis1)] * bc[(basis2, basis)]
                    bc[(basis2, basis1)] = inv
                    bc[(basis1, basis2)] = inv.inverse()
                    break
            else:
                raise ValueError(("the change of basis from '{!r}' to '{!r}'"
                                + " cannot be computed"
                                ).format(basis1, basis2))
        return bc[(basis1, basis2)]

    def set_change_of_basis(self, basis1, basis2, change_of_basis,
                            compute_inverse=True):
        r"""
        Relates two bases by an automorphism of ``self``.

        This updates the internal dictionary ``self._basis_changes``.

        INPUT:

        - ``basis1`` -- basis 1, denoted `(e_i)` below
        - ``basis2`` -- basis 2, denoted `(f_i)` below
        - ``change_of_basis`` -- instance of class
          :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`
          describing the automorphism `P` that relates the basis `(e_i)` to
          the basis `(f_i)` according to `f_i = P(e_i)`
        - ``compute_inverse`` -- boolean (default: ``True``); if set to ``True``,
          the inverse automorphism is computed and the change from basis `(f_i)`
          to `(e_i)` is set to it in the internal dictionary
          ``self._basis_changes``

        EXAMPLES:

        Defining a change of basis on a rank-2 free module::

            sage: M = FiniteRankFreeModule(QQ, 2, name='M')
            sage: e = M.basis('e')
            sage: f = M.basis('f')
            sage: a = M.automorphism()
            sage: a[:] = [[1, 2], [-1, 3]]
            sage: M.set_change_of_basis(e, f, a)

        The change of basis and its inverse have been recorded::

            sage: M.change_of_basis(e,f).matrix(e)
            [ 1  2]
            [-1  3]
            sage: M.change_of_basis(f,e).matrix(e)
            [ 3/5 -2/5]
            [ 1/5  1/5]

        and are effective::

            sage: f[0].display(e)
            f_0 = e_0 - e_1
            sage: e[0].display(f)
            e_0 = 3/5 f_0 + 1/5 f_1
        """
        if basis1 not in self._known_bases:
            raise TypeError("{} is not a basis of the {}".format(basis1,
                                                                 self))
        if basis2 not in self._known_bases:
            raise TypeError("{} is not a basis of the {}".format(basis2,
                                                                 self))
        if change_of_basis not in self.general_linear_group():
            raise TypeError("{} is not an automorphism of the {}".format(
                                                        change_of_basis, self))
        self._basis_changes[(basis1, basis2)] = change_of_basis
        if compute_inverse:
            self._basis_changes[(basis2, basis1)] = change_of_basis.inverse()

    def hom(self, codomain, matrix_rep, bases=None, name=None,
            latex_name=None):
        r"""
        Homomorphism from ``self`` to a free module.

        Define a module homomorphism

        .. MATH::

            \phi:\ M \longrightarrow N,

        where `M` is ``self`` and  `N` is a free module of finite rank
        over the same ring `R` as ``self``.

        .. NOTE::

            This method is a redefinition of
            :meth:`sage.structure.parent.Parent.hom` because the latter assumes
            that ``self`` has some privileged generators, while an instance of
            :class:`FiniteRankFreeModule` has no privileged basis.

        INPUT:

        - ``codomain`` -- the target module `N`
        - ``matrix_rep`` -- matrix of size rank(N)*rank(M) representing the
          homomorphism with respect to the pair of bases defined by ``bases``;
          this entry can actually be any material from which a matrix of
          elements of `R` can be constructed; the *columns* of
          ``matrix_rep`` must be the components w.r.t. ``basis_N`` of
          the images of the elements of ``basis_M``.
        - ``bases`` -- (default: ``None``) pair ``(basis_M, basis_N)`` defining
          the matrix representation, ``basis_M`` being a basis of ``self`` 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.

        OUTPUT:

        - the homomorphism `\phi: M \rightarrow N` corresponding to the given
          specifications, as an instance of
          :class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism`

        EXAMPLES:

        Homomorphism between two free modules over `\ZZ`::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: N = FiniteRankFreeModule(ZZ, 2, name='N')
            sage: e = M.basis('e')
            sage: f = N.basis('f')
            sage: phi = M.hom(N, [[-1,2,0], [5,1,2]]) ; phi
            Generic morphism:
              From: Rank-3 free module M over the Integer Ring
              To:   Rank-2 free module N over the Integer Ring

        Homomorphism defined by a matrix w.r.t. bases that are not the
        default ones::

            sage: ep = M.basis('ep', latex_symbol=r"e'")
            sage: fp = N.basis('fp', latex_symbol=r"f'")
            sage: phi = M.hom(N, [[3,2,1], [1,2,3]], bases=(ep, fp)) ; phi
            Generic morphism:
              From: Rank-3 free module M over the Integer Ring
              To:   Rank-2 free module N over the Integer Ring

        Call with all arguments specified::

            sage: phi = M.hom(N, [[3,2,1], [1,2,3]], bases=(ep, fp),
            ....:             name='phi', latex_name=r'\phi')

        The parent::

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

        See class
        :class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism`
        for more documentation.
        """
        homset = Hom(self, codomain)
        return homset(matrix_rep, bases=bases, name=name,
                      latex_name=latex_name)

    def endomorphism(self, matrix_rep, basis=None, name=None, latex_name=None):
        r"""
        Construct an endomorphism of the free module ``self``.

        The returned object is a module morphism `\phi: M \rightarrow M`,
        where `M` is ``self``.

        INPUT:

        - ``matrix_rep`` -- matrix of size rank(M)*rank(M) representing the
          endomorphism with respect to ``basis``;
          this entry can actually be any material from which a matrix of
          elements of ``self`` base ring can be constructed; the *columns* of
          ``matrix_rep`` must be the components w.r.t. ``basis`` of
          the images of the elements of ``basis``.
        - ``basis`` -- (default: ``None``) basis of ``self`` defining the
          matrix representation; if None the default basis of ``self`` is
          assumed.
        - ``name`` -- (default: ``None``) string; name given to the
          endomorphism
        - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote
          the endomorphism. If none is provided, ``name`` will be used.

        OUTPUT:

        - the endomorphism `\phi: M \rightarrow M` corresponding to the given
          specifications, as an instance of
          :class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism`

        EXAMPLES:

        Construction of an endomorphism with minimal data (module's default
        basis and no name)::

            sage: M = FiniteRankFreeModule(ZZ, 2, name='M')
            sage: e = M.basis('e')
            sage: phi = M.endomorphism([[1,-2], [-3,4]]) ; phi
            Generic endomorphism of Rank-2 free module M over the Integer Ring
            sage: phi.matrix()  # matrix w.r.t the default basis
            [ 1 -2]
            [-3  4]

        Construction with full list of arguments (matrix given a basis
        different from the default one)::

            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,-2], [-3,4]], basis=ep, name='phi',
            ....:                      latex_name=r'\phi')
            sage: phi
            Generic endomorphism of Rank-2 free module M over the Integer Ring
            sage: phi.matrix(ep)  # the input matrix
            [ 1 -2]
            [-3  4]
            sage: phi.matrix()  # matrix w.r.t the default basis
            [4 3]
            [2 1]

        See :class:`~sage.tensor.modules.free_module_morphism.FiniteRankFreeModuleMorphism`
        for more documentation.
        """
        from sage.categories.homset import End
        if basis is None:
            basis = self.default_basis()
        return End(self)(matrix_rep, bases=(basis,basis), name=name,
                         latex_name=latex_name)

    def identity_map(self, name='Id', latex_name=None):
        r"""
        Return the identity map of the free module ``self``.

        INPUT:

        - ``name`` -- (string; default: 'Id') name given to the identity
          identity map
        - ``latex_name`` -- (string; default: ``None``) LaTeX symbol to denote
          the identity map; if none is provided, the LaTeX symbol is set to
          '\mathrm{Id}' if ``name`` is 'Id' and to ``name`` otherwise

        OUTPUT:

        - the identity map of ``self`` as an instance of
          :class:`~sage.tensor.modules.free_module_automorphism.FreeModuleAutomorphism`

        EXAMPLES:

        Identity map of a rank-3 `\ZZ`-module::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: Id = M.identity_map() ; Id
            Identity map of the Rank-3 free module M over the Integer Ring
            sage: Id.parent()
            General linear group of the Rank-3 free module M over the Integer Ring
            sage: Id.matrix(e)
            [1 0 0]
            [0 1 0]
            [0 0 1]

        The default LaTeX symbol::

            sage: latex(Id)
            \mathrm{Id}

        It can be changed by means of the method
        :meth:`~sage.tensor.modules.free_module_tensor.FreeModuleTensor.set_name`::

            sage: Id.set_name(latex_name=r'\mathrm{1}_M')
            sage: latex(Id)
            \mathrm{1}_M

        The identity map is actually the identity element of GL(M)::

            sage: Id is M.general_linear_group().one()
            True

        It is also a tensor of type-`(1,1)` on M::

            sage: Id.tensor_type()
            (1, 1)
            sage: Id.comp(e)
            Kronecker delta of size 3x3
            sage: Id[:]
            [1 0 0]
            [0 1 0]
            [0 0 1]

        Example with a LaTeX symbol different from the default one and set
        at the creation of the object::

            sage: N = FiniteRankFreeModule(ZZ, 3, name='N')
            sage: f = N.basis('f')
            sage: Id = N.identity_map(name='Id_N', latex_name=r'\mathrm{Id}_N')
            sage: Id
            Identity map of the Rank-3 free module N over the Integer Ring
            sage: latex(Id)
            \mathrm{Id}_N
        """
        if self._identity_map is None:
            self._identity_map = self.general_linear_group().one()
            if name != 'Id':
                if latex_name is None:
                    latex_name = name
                self._identity_map.set_name(name=name, latex_name=latex_name)
        return self._identity_map


class FiniteRankDualFreeModule(ReflexiveModule_dual, FiniteRankFreeModule_abstract):
    r"""
    Dual of a free module of finite rank over a commutative ring.

    Given a free module `M` of finite rank over a commutative ring `R`,
    the *dual of* `M` is the set `M^*` of all linear forms on `M`,
    i.e., linear maps

    .. MATH::

        M \longrightarrow R

    This is a Sage *parent* class, whose *element* class is
    :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`.

    INPUT:

    - ``fmodule`` -- free module `M` of finite rank, as an instance of
      :class:`~sage.tensor.modules.finite_rank_free_module.FiniteRankFreeModule`
    - ``name`` -- (default: ``None``) string; name given to `M^*`
    - ``latex_name`` -- (default: ``None``) string; LaTeX symbol to denote `M^*`

    EXAMPLES::

        sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
        sage: e = M.basis('e')
        sage: A = M.dual(); A
        Dual of the Rank-3 free module M over the Integer Ring

    ``A`` is a module (actually a free module) over `\ZZ`::

        sage: A.category()
        Category of finite dimensional modules over Integer Ring
        sage: A in Modules(ZZ)
        True
        sage: A.rank()
        3
        sage: A.base_ring()
        Integer Ring
        sage: A.base_module()
        Rank-3 free module M over the Integer Ring

    ``A`` is a *parent* object, whose elements are linear forms,
    represented by instances of the class
    :class:`~sage.tensor.modules.free_module_alt_form.FreeModuleAltForm`::

        sage: a = A.an_element() ; a
        Linear form on the Rank-3 free module M over the Integer Ring
        sage: a.display() # expansion with respect to M's default basis (e)
        e^0
        sage: from sage.tensor.modules.free_module_alt_form import FreeModuleAltForm
        sage: isinstance(a, FreeModuleAltForm)
        True
        sage: a in A
        True
        sage: A.is_parent_of(a)
        True

    Elements can be constructed from ``A``. In particular, 0 yields
    the zero element of ``A``::

        sage: A(0)
        Linear form zero on the Rank-3 free module M over the Integer Ring
        sage: A(0) is A.zero()
        True

    while nonzero elements are constructed by providing their components in a
    given basis::

        sage: e
        Basis (e_0,e_1,e_2) on the Rank-3 free module M over the Integer Ring
        sage: comp = [0,3,-1]
        sage: a = A(comp, basis=e, name='a') ; a
        Linear form a on the Rank-3 free module M over the Integer Ring
        sage: a.display(e)
        a = 3 e^1 - e^2

    An alternative is to construct the alternating form from an empty list of
    components and to set the nonzero components afterwards::

        sage: a = A([], name='a')
        sage: a.set_comp(e)[0] = 3
        sage: a.set_comp(e)[1] = -1
        sage: a.set_comp(e)[2] = 4
        sage: a.display(e)
        a = 3 e^0 - e^1 + 4 e^2

    The dual is unique::

        sage: A is M.dual()
        True

    The exterior power `\Lambda^1(M^*)` is nothing but `M^*`::

        sage: M.dual_exterior_power(1) is M.dual()
        True

    It also coincides with the module of type-`(0,1)` tensors::

        sage: M.dual_exterior_power(1) is M.tensor_module(0,1)
        True
    """

    Element = FreeModuleAltForm

    def __init__(self, fmodule, name=None, latex_name=None):
        r"""
        TESTS::

            sage: from sage.tensor.modules.finite_rank_free_module import FiniteRankDualFreeModule
            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: A = FiniteRankDualFreeModule(M) ; A
            Dual of the Rank-3 free module M over the Integer Ring
            sage: TestSuite(A).run()
        """
        self._fmodule = fmodule
        rank = fmodule._rank
        if name is None and fmodule._name is not None:
            name = fmodule._name + '*'
        if latex_name is None and fmodule._latex_name is not None:
            latex_name = fmodule._latex_name + r'^*'
        super().__init__(fmodule._ring, rank, name=name,
                         latex_name=latex_name)
        fmodule._all_modules.add(self)

    #### Parent methods

    def _element_constructor_(self, comp=[], basis=None, name=None,
                              latex_name=None):
        r"""
        Construct a linear form.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: A = M.dual()
            sage: a = A._element_constructor_(0) ; a
            Linear form zero on the Rank-3 free module M over the Integer Ring
            sage: a = A._element_constructor_([2,0,-1], name='a') ; a
            Linear form a on the Rank-3 free module M over the Integer Ring
            sage: a.display()
            a = 2 e^0 - e^2
        """
        if isinstance(comp, (int, Integer)) and comp == 0:
            return self.zero()
        if isinstance(comp, FreeModuleTensor):
            # coercion of a tensor of type (0,1) to a linear form
            tensor = comp # for readability
            if tensor.tensor_type() == (0,1) and self._degree == 1 and \
                                         tensor.base_module() is self._fmodule:
                resu = self.element_class(self._fmodule, 1, name=tensor._name,
                                          latex_name=tensor._latex_name)
                for basis, comp in tensor._components.items():
                    resu._components[basis] = comp.copy()
                return resu
            raise TypeError("cannot coerce the {} ".format(tensor) +
                            "to an element of {}".format(self))
        # standard construction
        resu = self.element_class(self._fmodule, 1, name=name, latex_name=latex_name)
        if comp:
            resu.set_comp(basis)[:] = comp
        return resu

    def _an_element_(self):
        r"""
        Construct some (unnamed) alternating form.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(QQ, 4, name='M')
            sage: e = M.basis('e')
            sage: a = M.dual()._an_element_() ; a
            Linear form on the 4-dimensional vector space M over the Rational
             Field
            sage: a.display()
            1/2 e^0

        TESTS:

        When the base module has no default basis, a default
        basis will be set for it::

            sage: M2 = FiniteRankFreeModule(QQ, 4, name='M2')
            sage: a = M2.dual()._an_element_(); a
            Linear form on the 4-dimensional vector space M2 over the Rational Field
            sage: a + a
            Linear form on the 4-dimensional vector space M2 over the Rational Field
            sage: M2.default_basis()
            Basis (e_0,e_1,e_2,e_3) on the 4-dimensional vector space M2 over the Rational Field
        """
        resu = self.element_class(self._fmodule, 1)
        # Make sure that the base module has a default basis
        self._fmodule.an_element()
        sindex = self._fmodule._sindex
        ind = [sindex + i for i in range(resu._tensor_rank)]
        resu.set_comp()[ind] = self._fmodule._ring.an_element()
        return resu

    #### End of parent methods

    @cached_method
    def zero(self):
        r"""
        Return the zero of ``self``.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 3, name='M')
            sage: e = M.basis('e')
            sage: A = M.dual()
            sage: A.zero()
            Linear form zero on the Rank-3 free module M over the Integer Ring
            sage: A(0) is A.zero()
            True
        """
        resu = self._element_constructor_(name='zero', latex_name='0')
        for basis in self._fmodule._known_bases:
            resu._components[basis] = resu._new_comp(basis)
            # (since new components are initialized to zero)
        resu._is_zero = True # This element is certainly zero
        resu.set_immutable()
        return resu

    def _repr_(self):
        r"""
        Return a string representation of ``self``.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 5, name='M')
            sage: M.dual_exterior_power(1)._repr_()
            'Dual of the Rank-5 free module M over the Integer Ring'
        """
        return "Dual of the {}".format(self._fmodule)

    def base_module(self):
        r"""
        Return the free module on which ``self`` is constructed.

        OUTPUT:

        - instance of :class:`FiniteRankFreeModule` representing the free
          module on which the dual is defined.

        EXAMPLES::

            sage: M = FiniteRankFreeModule(ZZ, 5, name='M')
            sage: A = M.dual()
            sage: A.base_module()
            Rank-5 free module M over the Integer Ring
            sage: A.base_module() is M
            True
        """
        return self._fmodule
