Finitely presented graded modules - Modules

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

# Finitely presented graded modules

Let \(R\) be a connected graded algebra. A finitely presented module over \(R\) is a module isomorphic to the cokernel of an \(R\)-linear homomorphism \(f: F_1 \to F_0\) of finitely generated free modules: the generators of \(F_0\) correspond to the generators of the module, and the generators of \(F_1\) correspond to its relations, via the map \(f\).

This module class takes as input a set of generators and relations and uses them to construct a presentation, using the class `FreeGradedModuleMorphism`. It also allows such a morphism as input.

This package was designed with homological algebra in mind, and its API focuses on maps rather than objects. A good example of this is the kernel function `sage.modules.fp_graded.morphism.FPModuleMorphism.kernel_inclusion()`, which computes the kernel of a homomorphism \(f: M\to N\). Its return value is not an instance of the module class, but rather an injective homomorphism \(i: K\to M\) with the property that \(\operatorname{im}(i) = \ker(f)\).

Note

Some methods here require in addition that \(R\) be an algebra over a field or a PID and that Sage has a description of a basis for \(R\).

AUTHORS:

- Robert R. Bruner, Michael J. Catanzaro (2012): Initial version.

- Sverre Lunoee–Nielsen and Koen van Woerden (2019-11-29): Updated the original software to Sage version 8.9.

- Sverre Lunoee–Nielsen (2020-07-01): Refactored the code and added new documentation and tests.

class sage.modules.fp_graded.module.FPModule(j, names)

  Bases: `UniqueRepresentation`, `IndexedGenerators`, `Module`

  A finitely presented module over a connected graded algebra.

  INPUT:

  One of the following:

  - `arg0` – a morphism such that the module is the cokernel, or a free graded module, in which case the output is the same module, viewed as finitely presented

  Otherwise:

  - `arg0` – the graded connected algebra over which the module is defined; this algebra must be equipped with a graded basis

  - `generator_degrees` – tuple of integer degrees

  - `relations` – tuple of relations; a relation is a tuple of coefficients \((c_1, \ldots, c_n)\), ordered so that they correspond to the module generators, that is, such a tuple corresponds to the relation

    \[c_1 g_1 + \ldots + c_n g_n = 0\]

    if the generators are \((g_1, \ldots, g_n)\)

  EXAMPLES:

  Sage

      sage: from sage.modules.fp_graded.module import FPModule

      sage: E.<x,y> = ExteriorAlgebra(QQ)
      sage: M = FPModule(E, [0, 1], [[x, 1]])
      sage: a, b = M.generators()
      sage: x*a + b == 0
      True
      sage: (x*a + b).normalize()
      0

      sage: A3 = SteenrodAlgebra(2, profile=(4,3,2,1))
      sage: M = FPModule(A3, [0, 1], [[Sq(2), Sq(1)]])
      sage: M.generators()
      (g[0], g[1])
      sage: M.relations()
      (Sq(2)*g[0] + Sq(1)*g[1],)
      sage: M.is_trivial()
      False

      sage: Z = FPModule(A3, [])
      sage: Z.generators()
      ()
      sage: Z.relations()
      ()
      sage: Z.is_trivial()
      True

      sage: from sage.modules.fp_graded.free_module import FreeGradedModule
      sage: F = FreeGradedModule(E, [0, 1])
      sage: one = Hom(F, F).identity()
      sage: Z = FPModule(one)
      sage: Z.is_trivial()
      True

      sage: FPModule(E.free_graded_module([0, 1]))
      Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field

  Python

      >>> from sage.all import *
      >>> from sage.modules.fp_graded.module import FPModule

      >>> E = ExteriorAlgebra(QQ, names=('x', 'y',)); (x, y,) = E._first_ngens(2)
      >>> M = FPModule(E, [Integer(0), Integer(1)], [[x, Integer(1)]])
      >>> a, b = M.generators()
      >>> x*a + b == Integer(0)
      True
      >>> (x*a + b).normalize()
      0

      >>> A3 = SteenrodAlgebra(Integer(2), profile=(Integer(4),Integer(3),Integer(2),Integer(1)))
      >>> M = FPModule(A3, [Integer(0), Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]])
      >>> M.generators()
      (g[0], g[1])
      >>> M.relations()
      (Sq(2)*g[0] + Sq(1)*g[1],)
      >>> M.is_trivial()
      False

      >>> Z = FPModule(A3, [])
      >>> Z.generators()
      ()
      >>> Z.relations()
      ()
      >>> Z.is_trivial()
      True

      >>> from sage.modules.fp_graded.free_module import FreeGradedModule
      >>> F = FreeGradedModule(E, [Integer(0), Integer(1)])
      >>> one = Hom(F, F).identity()
      >>> Z = FPModule(one)
      >>> Z.is_trivial()
      True

      >>> FPModule(E.free_graded_module([Integer(0), Integer(1)]))
      Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field

  Element

    alias of `FPElement`

  an_element(n=None)

    An element of this module.

    This function chooses deterministically an element, i.e. the output depends only on the module and its input `n`.

    INPUT:

    - `n` – (optional) the degree of the element to construct

    OUTPUT: a module element of the given degree

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))
        sage: M = FPModule(A2, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]])

        sage: [M.an_element(i) for i in range(10)]
        [g[0],
         Sq(1)*g[0],
         Sq(2)*g[0] + g[2],
         Sq(0,1)*g[0] + Sq(1)*g[2],
         Sq(1,1)*g[0] + Sq(2)*g[2] + g[4],
         Sq(2,1)*g[0] + Sq(0,1)*g[2] + Sq(1)*g[4],
         Sq(0,2)*g[0] + Sq(1,1)*g[2] + Sq(2)*g[4],
         Sq(0,0,1)*g[0] + Sq(2,1)*g[2] + Sq(0,1)*g[4],
         Sq(1,0,1)*g[0] + Sq(6)*g[2] + Sq(1,1)*g[4],
         Sq(2,0,1)*g[0] + Sq(4,1)*g[2] + Sq(2,1)*g[4]]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))
        >>> M = FPModule(A2, [Integer(0),Integer(2),Integer(4)], [[Integer(0), Sq(Integer(5)), Sq(Integer(3))], [Sq(Integer(7)), Integer(0), Sq(Integer(2))*Sq(Integer(1))]])

        >>> [M.an_element(i) for i in range(Integer(10))]
        [g[0],
         Sq(1)*g[0],
         Sq(2)*g[0] + g[2],
         Sq(0,1)*g[0] + Sq(1)*g[2],
         Sq(1,1)*g[0] + Sq(2)*g[2] + g[4],
         Sq(2,1)*g[0] + Sq(0,1)*g[2] + Sq(1)*g[4],
         Sq(0,2)*g[0] + Sq(1,1)*g[2] + Sq(2)*g[4],
         Sq(0,0,1)*g[0] + Sq(2,1)*g[2] + Sq(0,1)*g[4],
         Sq(1,0,1)*g[0] + Sq(6)*g[2] + Sq(1,1)*g[4],
         Sq(2,0,1)*g[0] + Sq(4,1)*g[2] + Sq(2,1)*g[4]]

  basis_elements(n, verbose=False)

    Return a basis for the free module of degree `n` module elements.

    Note

    Suppose `self` is a module over the graded algebra \(A\) with base ring \(R\). This returns a basis as a free module over \(R\).

    INPUT:

    - `n` – integer

    - `verbose` – boolean (default: `False`); controls whether log messages should be emitted

    OUTPUT:

    A list of homogeneous module elements of degree `n` which is a basis for the free module of all degree `n` module elements.

    See also

    `vector_presentation()`, `element_from_coordinates()`

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))
        sage: M.<m0,m2> = FPModule(A2, [0,2], [[Sq(4), Sq(2)], [0, Sq(6)]])

        sage: M.basis_elements(4)
        (Sq(1,1)*m0, Sq(4)*m0)

        sage: M.basis_elements(5)
        (Sq(2,1)*m0, Sq(5)*m0, Sq(0,1)*m2)

        sage: M.basis_elements(25)
        ()

        sage: M.basis_elements(0)
        (m0,)

        sage: M.basis_elements(2)
        (Sq(2)*m0, m2)

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))
        >>> M = FPModule(A2, [Integer(0),Integer(2)], [[Sq(Integer(4)), Sq(Integer(2))], [Integer(0), Sq(Integer(6))]], names=('m0', 'm2',)); (m0, m2,) = M._first_ngens(2)

        >>> M.basis_elements(Integer(4))
        (Sq(1,1)*m0, Sq(4)*m0)

        >>> M.basis_elements(Integer(5))
        (Sq(2,1)*m0, Sq(5)*m0, Sq(0,1)*m2)

        >>> M.basis_elements(Integer(25))
        ()

        >>> M.basis_elements(Integer(0))
        (m0,)

        >>> M.basis_elements(Integer(2))
        (Sq(2)*m0, m2)

  change_ring(algebra)

    Change the base ring of `self`.

    INPUT:

    - `algebra` – a connected graded algebra

    OUTPUT:

    The finitely presented module over `algebra` defined with the exact same number of generators of the same degrees and relations as `self`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A = SteenrodAlgebra(2)
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))

        sage: M = FPModule(A, [0,1], [[Sq(2), Sq(1)]])
        sage: N = M.change_ring(A2); N
        Finitely presented left module on 2 generators and 1 relation over
         sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A = SteenrodAlgebra(Integer(2))
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A, [Integer(0),Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]])
        >>> N = M.change_ring(A2); N
        Finitely presented left module on 2 generators and 1 relation over
         sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]

    Changing back yields the original module:

    Sage

        sage: N.change_ring(A) is M
        True

    [Python]

        >>> from sage.all import *
        >>> N.change_ring(A) is M
        True

  connectivity()

    The connectivity of `self`.

    Since a finitely presented module over a connected algebra is in particular bounded below, the connectivity is an integer when the module is non-trivial, and \(+\infty\) when the module is trivial.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A = SteenrodAlgebra(2)

        sage: M = FPModule(A, [0,2,4], [[0, Sq(5), Sq(3)], [Sq(7), 0, Sq(2)*Sq(1)]])
        sage: M.connectivity()
        0

        sage: G = FPModule(A, [0,2], [[1,0]])
        sage: G.connectivity()
        2

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A = SteenrodAlgebra(Integer(2))

        >>> M = FPModule(A, [Integer(0),Integer(2),Integer(4)], [[Integer(0), Sq(Integer(5)), Sq(Integer(3))], [Sq(Integer(7)), Integer(0), Sq(Integer(2))*Sq(Integer(1))]])
        >>> M.connectivity()
        0

        >>> G = FPModule(A, [Integer(0),Integer(2)], [[Integer(1),Integer(0)]])
        >>> G.connectivity()
        2

  defining_homomorphism()

    Return the homomorphism defining `self`.

    `self` is a finitely presented module defined as the cokernel of a map \(j: F_0 o F_1\) of free modules, and this returns that map.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: E.<x,y> = ExteriorAlgebra(QQ)
        sage: M = FPModule(E, [0, 1], [[x, 1]])
        sage: M.defining_homomorphism()
        Module morphism:
          From: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
          To:   Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
          Defn: g[1] |--> x*g[0] + g[1]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> E = ExteriorAlgebra(QQ, names=('x', 'y',)); (x, y,) = E._first_ngens(2)
        >>> M = FPModule(E, [Integer(0), Integer(1)], [[x, Integer(1)]])
        >>> M.defining_homomorphism()
        Module morphism:
          From: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
          To:   Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
          Defn: g[1] |--> x*g[0] + g[1]

  element_from_coordinates(coordinates, n)

    Return the module element in degree `n` having the given coordinates with respect to the basis returned by `basis_elements()`.

    This function is inverse to `sage.modules.fp_graded.element.FPElement.vector_presentation()`.

    INPUT:

    - `coordinates` – a vector of coordinates

    - `n` – the degree of the element to construct

    OUTPUT:

    A module element of degree `n` having the given coordinates with respect to the basis returned by `basis_elements()`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A = SteenrodAlgebra(2)
        sage: M = FPModule(A, [0], [[Sq(4)], [Sq(7)], [Sq(4)*Sq(9)]])

        sage: M.vector_presentation(12).dimension()
        3
        sage: x = M.element_from_coordinates((0,1,0), 12); x
        Sq(0,4)*g[0]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A = SteenrodAlgebra(Integer(2))
        >>> M = FPModule(A, [Integer(0)], [[Sq(Integer(4))], [Sq(Integer(7))], [Sq(Integer(4))*Sq(Integer(9))]])

        >>> M.vector_presentation(Integer(12)).dimension()
        3
        >>> x = M.element_from_coordinates((Integer(0),Integer(1),Integer(0)), Integer(12)); x
        Sq(0,4)*g[0]

    Applying the inverse function brings us back to the coordinate form:

    Sage

        sage: x.vector_presentation()
        (0, 1, 0)

    [Python]

        >>> from sage.all import *
        >>> x.vector_presentation()
        (0, 1, 0)

    See also

    `sage.modules.fp_graded.module.FPModule.vector_presentation()`

  gen(index)

    alias of `generator()`.

  generator(index)

    Return the module generator with the given index.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1))

        sage: M = FPModule(A4, [0,2,3])
        sage: M.generator(0)
        g[0]

        sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h')
        sage: N.generator(1)
        h[1]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A4 = SteenrodAlgebra(Integer(2), profile=(Integer(4),Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A4, [Integer(0),Integer(2),Integer(3)])
        >>> M.generator(Integer(0))
        g[0]

        >>> N = FPModule(A4, [Integer(0), Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]], names='h')
        >>> N.generator(Integer(1))
        h[1]

  generator_degrees()

    Return the degrees of the generators for `self`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1))
        sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]])

        sage: N.generator_degrees()
        (0, 1)

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A4 = SteenrodAlgebra(Integer(2), profile=(Integer(4),Integer(3),Integer(2),Integer(1)))
        >>> N = FPModule(A4, [Integer(0), Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]])

        >>> N.generator_degrees()
        (0, 1)

  generators()

    Return the generators of `self`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1))

        sage: M = FPModule(A4, [0,0,2,3])
        sage: M.generators()
        (g[0, 0], g[0, 1], g[2, 0], g[3, 0])

        sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]], names='h')
        sage: N.generators()
        (h[0], h[1])

        sage: Z = FPModule(A4, [])
        sage: Z.generators()
        ()

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A4 = SteenrodAlgebra(Integer(2), profile=(Integer(4),Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A4, [Integer(0),Integer(0),Integer(2),Integer(3)])
        >>> M.generators()
        (g[0, 0], g[0, 1], g[2, 0], g[3, 0])

        >>> N = FPModule(A4, [Integer(0), Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]], names='h')
        >>> N.generators()
        (h[0], h[1])

        >>> Z = FPModule(A4, [])
        >>> Z.generators()
        ()

  gens()

    alias of `generators()`.

  has_relations()

    Return `True` if no relations are defined, and `False` otherwise.

    Note

    This module is free if this function returns `False`, but a free module can have (redundant) relations.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))

        sage: F = FPModule(A2, [1,2])
        sage: F.has_relations()
        False

        sage: M = FPModule(A2, [1,2], [[Sq(2), Sq(1)]])
        sage: M.has_relations()
        True

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))

        >>> F = FPModule(A2, [Integer(1),Integer(2)])
        >>> F.has_relations()
        False

        >>> M = FPModule(A2, [Integer(1),Integer(2)], [[Sq(Integer(2)), Sq(Integer(1))]])
        >>> M.has_relations()
        True

    A free module constructed with a redundant generator and relation:

    Sage

        sage: N = FPModule(A2, [0, 0], [[0, 1]])
        sage: N.has_relations()
        True
        sage: # Computing a minimal presentation reveals an
        ....: # isomorphic module with no relations.
        sage: N_min = N.minimal_presentation().domain()
        sage: N_min.has_relations()
        False

    [Python]

        >>> from sage.all import *
        >>> N = FPModule(A2, [Integer(0), Integer(0)], [[Integer(0), Integer(1)]])
        >>> N.has_relations()
        True
        >>> # Computing a minimal presentation reveals an
        ... # isomorphic module with no relations.
        >>> N_min = N.minimal_presentation().domain()
        >>> N_min.has_relations()
        False

  is_trivial()

    Return `True` if `self` is isomorphic to the trivial module and `False` otherwise.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A = SteenrodAlgebra(2)
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))

        sage: M = FPModule(A2, [])
        sage: M.is_trivial()
        True

        sage: N = FPModule(A, [1,2])
        sage: N.is_trivial()
        False

        sage: P = FPModule(A, [1,2], [[1,0], [0,1]])
        sage: P.is_trivial()
        True

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A = SteenrodAlgebra(Integer(2))
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A2, [])
        >>> M.is_trivial()
        True

        >>> N = FPModule(A, [Integer(1),Integer(2)])
        >>> N.is_trivial()
        False

        >>> P = FPModule(A, [Integer(1),Integer(2)], [[Integer(1),Integer(0)], [Integer(0),Integer(1)]])
        >>> P.is_trivial()
        True

  minimal_presentation(top_dim=None, verbose=False)

    Return a minimal presentation of `self`.

    OUTPUT:

    An isomorphism \(M \to S\), where \(M\) has minimal presentation and \(S\) is `self`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))

        sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)],[0,Sq(2)],[Sq(3),0]])
        sage: i = M.minimal_presentation()
        sage: M_min = i.domain()

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A2, [Integer(0),Integer(1)], [[Sq(Integer(2)),Sq(Integer(1))],[Integer(0),Sq(Integer(2))],[Sq(Integer(3)),Integer(0)]])
        >>> i = M.minimal_presentation()
        >>> M_min = i.domain()

    `i` is an isomorphism between `M_min` and `M`:

    Sage

        sage: i.codomain() is M
        True
        sage: i.is_injective()
        True
        sage: i.is_surjective()
        True

    [Python]

        >>> from sage.all import *
        >>> i.codomain() is M
        True
        >>> i.is_injective()
        True
        >>> i.is_surjective()
        True

    There are more relations in `M` than in `M_min`:

    Sage

        sage: M.relations()
        (Sq(2)*g[0] + Sq(1)*g[1], Sq(2)*g[1], Sq(3)*g[0])
        sage: M_min.relations()
        (Sq(2)*g[0] + Sq(1)*g[1], Sq(2)*g[1])

    Python

        >>> from sage.all import *
        >>> M.relations()
        (Sq(2)*g[0] + Sq(1)*g[1], Sq(2)*g[1], Sq(3)*g[0])
        >>> M_min.relations()
        (Sq(2)*g[0] + Sq(1)*g[1], Sq(2)*g[1])

  monomial()

    Return the basis element indexed by `i`.

    INPUT:

    - `i` – an element of the index set

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]])
        sage: M.monomial(0)
        g[0]
        sage: M.monomial(1)
        g[1]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> M = FPModule(SteenrodAlgebra(Integer(2)), [Integer(0),Integer(1)], [[Sq(Integer(4)), Sq(Integer(3))]])
        >>> M.monomial(Integer(0))
        g[0]
        >>> M.monomial(Integer(1))
        g[1]

  relation(index)

    Return the module relation of the given index.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1))
        sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]])
        sage: N.relation(0)
        Sq(2)*g[0] + Sq(1)*g[1]

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A4 = SteenrodAlgebra(Integer(2), profile=(Integer(4),Integer(3),Integer(2),Integer(1)))
        >>> N = FPModule(A4, [Integer(0), Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]])
        >>> N.relation(Integer(0))
        Sq(2)*g[0] + Sq(1)*g[1]

  relations()

    Return the relations of `self`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A4 = SteenrodAlgebra(2, profile=(4,3,2,1))

        sage: M = FPModule(A4, [0,2,3])
        sage: M.relations()
        ()

        sage: N = FPModule(A4, [0, 1], [[Sq(2), Sq(1)]])
        sage: N.relations()
        (Sq(2)*g[0] + Sq(1)*g[1],)

        sage: Z = FPModule(A4, [])
        sage: Z.relations()
        ()

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A4 = SteenrodAlgebra(Integer(2), profile=(Integer(4),Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A4, [Integer(0),Integer(2),Integer(3)])
        >>> M.relations()
        ()

        >>> N = FPModule(A4, [Integer(0), Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]])
        >>> N.relations()
        (Sq(2)*g[0] + Sq(1)*g[1],)

        >>> Z = FPModule(A4, [])
        >>> Z.relations()
        ()

  resolution(k, top_dim=None, verbose=False)

    Return a free resolution of this module of length `k`.

    INPUT:

    - `k` – nonnegative integer

    - `top_dim` – stop the computation at this degree (default: `None`, but required if the algebra is not finite-dimensional)

    - `verbose` – boolean (default: `False`); control if log messages should be emitted

    OUTPUT: list of homomorphisms \([\epsilon, f_1, \ldots, f_k]\) such that

    \[f_i: F_i \to F_{i-1} \text{ for } 1 < i \leq k, \qquad \epsilon: F_0 \to M,\]

    where each \(F_i\) is a finitely generated free module, and the sequence

    \[F_k \xrightarrow{\mathit{f_k}} F_{k-1} \xrightarrow{\mathit{f_{k-1}}} \ldots \rightarrow F_0 \xrightarrow{\epsilon} M \rightarrow 0\]

    is exact. Note that the 0th element in this list is the map \(\epsilon\), and the rest of the maps are between free modules.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule

        sage: E.<x,y> = ExteriorAlgebra(QQ)
        sage: M = FPModule(E, [0], [[x], [y]])
        sage: res = M.resolution(3); res
        [Module morphism:
           From: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
           To:   Finitely presented left module on 1 generator and 2 relations over The exterior algebra of rank 2 over Rational Field
           Defn: g[0] |--> g[0],
         Module morphism:
           From: Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
           To:   Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
           Defn: g[1, 0] |--> x*g[0]
                 g[1, 1] |--> y*g[0],
         Module morphism:
           From: Free graded left module on 3 generators over The exterior algebra of rank 2 over Rational Field
           To:   Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
           Defn: g[2, 0] |--> x*g[1, 0]
                 g[2, 1] |--> y*g[1, 0] + x*g[1, 1]
                 g[2, 2] |--> y*g[1, 1],
         Module morphism:
           From: Free graded left module on 4 generators over The exterior algebra of rank 2 over Rational Field
           To:   Free graded left module on 3 generators over The exterior algebra of rank 2 over Rational Field
           Defn: g[3, 0] |--> x*g[2, 0]
                 g[3, 1] |--> y*g[2, 0] + x*g[2, 1]
                 g[3, 2] |--> y*g[2, 1] + x*g[2, 2]
                 g[3, 3] |--> y*g[2, 2]]
        sage: all((res[i] * res[i+1]).is_zero() for i in range(len(res)-1))
        True

        sage: e = SymmetricFunctions(QQ).e()
        sage: M = FPModule(e, [0], [[e[2]+e[1,1]], [e[1,1]]])
        sage: res = M.resolution(3, top_dim=10)
        sage: all((res[i] * res[i+1]).is_zero() for i in range(2))
        True
        sage: res[-1].domain().is_trivial()
        True
        sage: M = FPModule(e, [0,2], [[e[2]+e[1,1], 0], [e[2,1], e[1]], [0, e[1,1]]])
        sage: res = M.resolution(3, top_dim=10)
        sage: all((res[i] * res[i+1]).is_zero() for i in range(2))
        True
        sage: res[-1].domain().is_trivial()
        True

        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))
        sage: M = FPModule(A2, [0,1], [[Sq(2), Sq(1)]])
        sage: M.resolution(0)
        [Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[0] |--> g[0]
                 g[1] |--> g[1]]
        sage: res = M.resolution(4, verbose=True)
        Computing f_1 (1/4)
        Computing f_2 (2/4)
        Computing using the profile:
        (2, 1)
        Resolving the kernel in the range of dimensions [2, 8]: 2 3 4 5 6 7 8.
        Computing f_3 (3/4)
        Computing using the profile:
        (2, 1)
        Resolving the kernel in the range of dimensions [8, 14]: 8 9 10 11 12 13 14.
        Computing f_4 (4/4)
        Computing using the profile:
        (2, 1)
        Resolving the kernel in the range of dimensions [9, 16]: 9 10 11 12 13 14 15 16.
        sage: len(res)
        5
        sage: res
        [Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[0] |--> g[0]
                 g[1] |--> g[1],
         Module morphism:
           From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[2] |--> Sq(2)*g[0] + Sq(1)*g[1],
         Module morphism:
           From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[8] |--> Sq(3,1)*g[2],
         Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[9] |--> Sq(1)*g[8]
                 g[10] |--> Sq(2)*g[8],
         Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[10] |--> Sq(1)*g[9]
                 g[12] |--> Sq(0,1)*g[9] + Sq(2)*g[10]]
        sage: for i in range(len(res)-1):
        ....:     assert (res[i] * res[i+1]).is_zero(), 'the result is not a complex'

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule

        >>> E = ExteriorAlgebra(QQ, names=('x', 'y',)); (x, y,) = E._first_ngens(2)
        >>> M = FPModule(E, [Integer(0)], [[x], [y]])
        >>> res = M.resolution(Integer(3)); res
        [Module morphism:
           From: Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
           To:   Finitely presented left module on 1 generator and 2 relations over The exterior algebra of rank 2 over Rational Field
           Defn: g[0] |--> g[0],
         Module morphism:
           From: Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
           To:   Free graded left module on 1 generator over The exterior algebra of rank 2 over Rational Field
           Defn: g[1, 0] |--> x*g[0]
                 g[1, 1] |--> y*g[0],
         Module morphism:
           From: Free graded left module on 3 generators over The exterior algebra of rank 2 over Rational Field
           To:   Free graded left module on 2 generators over The exterior algebra of rank 2 over Rational Field
           Defn: g[2, 0] |--> x*g[1, 0]
                 g[2, 1] |--> y*g[1, 0] + x*g[1, 1]
                 g[2, 2] |--> y*g[1, 1],
         Module morphism:
           From: Free graded left module on 4 generators over The exterior algebra of rank 2 over Rational Field
           To:   Free graded left module on 3 generators over The exterior algebra of rank 2 over Rational Field
           Defn: g[3, 0] |--> x*g[2, 0]
                 g[3, 1] |--> y*g[2, 0] + x*g[2, 1]
                 g[3, 2] |--> y*g[2, 1] + x*g[2, 2]
                 g[3, 3] |--> y*g[2, 2]]
        >>> all((res[i] * res[i+Integer(1)]).is_zero() for i in range(len(res)-Integer(1)))
        True

        >>> e = SymmetricFunctions(QQ).e()
        >>> M = FPModule(e, [Integer(0)], [[e[Integer(2)]+e[Integer(1),Integer(1)]], [e[Integer(1),Integer(1)]]])
        >>> res = M.resolution(Integer(3), top_dim=Integer(10))
        >>> all((res[i] * res[i+Integer(1)]).is_zero() for i in range(Integer(2)))
        True
        >>> res[-Integer(1)].domain().is_trivial()
        True
        >>> M = FPModule(e, [Integer(0),Integer(2)], [[e[Integer(2)]+e[Integer(1),Integer(1)], Integer(0)], [e[Integer(2),Integer(1)], e[Integer(1)]], [Integer(0), e[Integer(1),Integer(1)]]])
        >>> res = M.resolution(Integer(3), top_dim=Integer(10))
        >>> all((res[i] * res[i+Integer(1)]).is_zero() for i in range(Integer(2)))
        True
        >>> res[-Integer(1)].domain().is_trivial()
        True

        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))
        >>> M = FPModule(A2, [Integer(0),Integer(1)], [[Sq(Integer(2)), Sq(Integer(1))]])
        >>> M.resolution(Integer(0))
        [Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[0] |--> g[0]
                 g[1] |--> g[1]]
        >>> res = M.resolution(Integer(4), verbose=True)
        Computing f_1 (1/4)
        Computing f_2 (2/4)
        Computing using the profile:
        (2, 1)
        Resolving the kernel in the range of dimensions [2, 8]: 2 3 4 5 6 7 8.
        Computing f_3 (3/4)
        Computing using the profile:
        (2, 1)
        Resolving the kernel in the range of dimensions [8, 14]: 8 9 10 11 12 13 14.
        Computing f_4 (4/4)
        Computing using the profile:
        (2, 1)
        Resolving the kernel in the range of dimensions [9, 16]: 9 10 11 12 13 14 15 16.
        >>> len(res)
        5
        >>> res
        [Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Finitely presented left module on 2 generators and 1 relation over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[0] |--> g[0]
                 g[1] |--> g[1],
         Module morphism:
           From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[2] |--> Sq(2)*g[0] + Sq(1)*g[1],
         Module morphism:
           From: Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[8] |--> Sq(3,1)*g[2],
         Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 1 generator over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[9] |--> Sq(1)*g[8]
                 g[10] |--> Sq(2)*g[8],
         Module morphism:
           From: Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           To:   Free graded left module on 2 generators over sub-Hopf algebra of mod 2 Steenrod algebra, milnor basis, profile function [3, 2, 1]
           Defn: g[10] |--> Sq(1)*g[9]
                 g[12] |--> Sq(0,1)*g[9] + Sq(2)*g[10]]
        >>> for i in range(len(res)-Integer(1)):
        ...     assert (res[i] * res[i+Integer(1)]).is_zero(), 'the result is not a complex'

    We construct \(\GF{3}\) as a \(\ZZ\)-module (with trivial grading concentrated in degree 0) and compute its resolution:

    Sage

        sage: E = ExteriorAlgebra(ZZ, 0)
        sage: M = FPModule(E, [0], [[3]])
        sage: res = M.resolution(3)
        sage: res
        [Module morphism:
           From: Free graded left module on 1 generator over The exterior algebra of rank 0 over Integer Ring
           To:   Finitely presented left module on 1 generator and 1 relation over The exterior algebra of rank 0 over Integer Ring
           Defn: g[0] |--> g[0],
         Module endomorphism of Free graded left module on 1 generator over The exterior algebra of rank 0 over Integer Ring
           Defn: g[0] |--> 3*g[0],
         Module morphism:
           From: Free graded left module on 0 generators over The exterior algebra of rank 0 over Integer Ring
           To:   Free graded left module on 1 generator over The exterior algebra of rank 0 over Integer Ring,
         Module endomorphism of Free graded left module on 0 generators over The exterior algebra of rank 0 over Integer Ring]

    [Python]

        >>> from sage.all import *
        >>> E = ExteriorAlgebra(ZZ, Integer(0))
        >>> M = FPModule(E, [Integer(0)], [[Integer(3)]])
        >>> res = M.resolution(Integer(3))
        >>> res
        [Module morphism:
           From: Free graded left module on 1 generator over The exterior algebra of rank 0 over Integer Ring
           To:   Finitely presented left module on 1 generator and 1 relation over The exterior algebra of rank 0 over Integer Ring
           Defn: g[0] |--> g[0],
         Module endomorphism of Free graded left module on 1 generator over The exterior algebra of rank 0 over Integer Ring
           Defn: g[0] |--> 3*g[0],
         Module morphism:
           From: Free graded left module on 0 generators over The exterior algebra of rank 0 over Integer Ring
           To:   Free graded left module on 1 generator over The exterior algebra of rank 0 over Integer Ring,
         Module endomorphism of Free graded left module on 0 generators over The exterior algebra of rank 0 over Integer Ring]

  submodule_inclusion(spanning_elements)

    Return the inclusion morphism of the submodule of `self` spanned by the given elements.

    INPUT:

    - `spanning_elements` – an iterable of elements

    OUTPUT: the inclusion of the submodule into this module

    Because a submodule of a finitely presented module need not be finitely presented, this method will only work if the underlying algebra is finite-dimensional. Indeed, the current implementation only works if the algebra has a `top_class` method, which gets used in `sage.modules.fp_graded.morphism._resolve_kernel()`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))

        sage: M = FPModule(A2, [0,1], [[Sq(2),Sq(1)]])
        sage: i = M.submodule_inclusion([M.generator(0)])
        sage: i.codomain() is M
        True
        sage: i.is_injective()
        True
        sage: i.domain().generator_degrees()
        (0,)
        sage: i.domain().relations()
        (Sq(3)*g[0],)

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))

        >>> M = FPModule(A2, [Integer(0),Integer(1)], [[Sq(Integer(2)),Sq(Integer(1))]])
        >>> i = M.submodule_inclusion([M.generator(Integer(0))])
        >>> i.codomain() is M
        True
        >>> i.is_injective()
        True
        >>> i.domain().generator_degrees()
        (0,)
        >>> i.domain().relations()
        (Sq(3)*g[0],)

  suspension(t)

    Return the suspension of `self` by degree `t`.

    INPUT:

    - `t` – integer degree by which the module is suspended

    OUTPUT:

    A module which is identical to this module by a shift of degrees by the integer `t`.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A = SteenrodAlgebra(2)
        sage: A2 = SteenrodAlgebra(2, profile=(3,2,1))

        sage: Y = FPModule(A2, [0], [[Sq(1)]])
        sage: X = Y.suspension(4)
        sage: X.generator_degrees()
        (4,)
        sage: X.relations()
        (Sq(1)*g[4],)

        sage: M = FPModule(A, [2,3], [[Sq(2), Sq(1)], [0, Sq(2)]])
        sage: Q = M.suspension(1)
        sage: Q.generator_degrees()
        (3, 4)
        sage: Q.relations()
        (Sq(2)*g[3] + Sq(1)*g[4], Sq(2)*g[4])
        sage: Q = M.suspension(-3)
        sage: Q.generator_degrees()
        (-1, 0)
        sage: Q = M.suspension(0)
        sage: Q.generator_degrees()
        (2, 3)

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A = SteenrodAlgebra(Integer(2))
        >>> A2 = SteenrodAlgebra(Integer(2), profile=(Integer(3),Integer(2),Integer(1)))

        >>> Y = FPModule(A2, [Integer(0)], [[Sq(Integer(1))]])
        >>> X = Y.suspension(Integer(4))
        >>> X.generator_degrees()
        (4,)
        >>> X.relations()
        (Sq(1)*g[4],)

        >>> M = FPModule(A, [Integer(2),Integer(3)], [[Sq(Integer(2)), Sq(Integer(1))], [Integer(0), Sq(Integer(2))]])
        >>> Q = M.suspension(Integer(1))
        >>> Q.generator_degrees()
        (3, 4)
        >>> Q.relations()
        (Sq(2)*g[3] + Sq(1)*g[4], Sq(2)*g[4])
        >>> Q = M.suspension(-Integer(3))
        >>> Q.generator_degrees()
        (-1, 0)
        >>> Q = M.suspension(Integer(0))
        >>> Q.generator_degrees()
        (2, 3)

  vector_presentation(n, verbose=False)

    Return a free module isomorphic to the free module of module elements of degree `n`.

    INPUT:

    - `n` – the degree of the presentation

    OUTPUT: a vector space

    See also

    `basis_elements()`, `element_from_coordinates()`

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: A = SteenrodAlgebra(2)
        sage: M = FPModule(A, [0,2,4], [[Sq(4),Sq(2),0]])

        sage: V = M.vector_presentation(4)
        sage: V.dimension()
        3

        sage: len(M.basis_elements(4))
        3

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> A = SteenrodAlgebra(Integer(2))
        >>> M = FPModule(A, [Integer(0),Integer(2),Integer(4)], [[Sq(Integer(4)),Sq(Integer(2)),Integer(0)]])

        >>> V = M.vector_presentation(Integer(4))
        >>> V.dimension()
        3

        >>> len(M.basis_elements(Integer(4)))
        3

  zero()

    Return the zero element.

    EXAMPLES:

    Sage

        sage: from sage.modules.fp_graded.module import FPModule
        sage: M = FPModule(SteenrodAlgebra(2), [0,1], [[Sq(4), Sq(3)]])
        sage: M.zero()
        0

    Python

        >>> from sage.all import *
        >>> from sage.modules.fp_graded.module import FPModule
        >>> M = FPModule(SteenrodAlgebra(Integer(2)), [Integer(0),Integer(1)], [[Sq(Integer(4)), Sq(Integer(3))]])
        >>> M.zero()
        0