Elements and maps of cohomology rings — "p_group_cohomology" 3.3.2 documentation

# Elements and maps of cohomology rings

AUTHORS:

- Simon King <simon.king@uni-jena.de>

This module provides elements of modular cohomology rings of groups of prime power order (`COCH`), of finite groups that are not of prime power order (`MODCOCH`), induced maps between cohomology rings (`ChMap`), and Yoneda cochains for prime power groups (`YCOCH`). While Yoneda cochains are just a tool for our implementation of Massey products and Kraines’ restricted Massey powers, the other three classes are vital for cohomology computations.

The class `COCH` provides elements of the mod-\(p\) cohomology of a finite \(p\)-group \(P\). It is based on a minimal free resolutions of \(F_pP\) provided by the class `RESL`. The cup product is computed by standard constructions from homological algebra.

In contrast, `MODCOCH` provides elements of the mod-\(p\) cohomology of any finite group \(G\). The underlying data are stable elements of the mod-\(p\) cohomology ring of a subgroup \(U\) of \(G\) whose index is coprime to \(p\). This ring is represented in the Singular interface. For instance, \(P\) may be a Sylow \(p\)-subgroup of \(G\). It is allowed that \(G=U\) is a finite \(p\)-group, but in this case, the cohomology ring of \(G\) must first be computed using `COCH`.

Group homomorphisms induce maps in cohomology, and this is provided by `ChMap`. Induced homomorphisms are essential for the computation of cohomology rings of finite groups that are not of prime power order: The conditions defining stable elements are expressed in terms of pairs of induced maps.

`COCH`, `MODCOCH` and `ChMap` can quite easily be combined, which can be seen in the following examples.

EXAMPLES:

We define two groups (one of them is of prime power order) and compute their cohomology rings.

    sage: from pGroupCohomology import CohomologyRing
    sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
    sage: S = libgap.SymmetricGroup(6)
    sage: D = libgap.DihedralGroup(8)
    sage: HS = CohomologyRing(S, prime=2, GroupName='Sym6', from_scratch=True)
    sage: HS.make()
    sage: HD = CohomologyRing(D, GroupName='D_8', from_scratch=True)
    sage: HD.make()

We do some computations with cohomology elements, testing relations in `HS` and `HD`:

    sage: cD1 = HD.1+HD.2*HD.3; cD1
    c_2_2+(b_1_0)*(b_1_1): 2-Cocycle in H^*(D_8; GF(2))
    sage: cD2 = HD.1+HD.3^2; cD2
    c_2_2+(b_1_1)**2: 2-Cocycle in H^*(D_8; GF(2))
    sage: cD1 == cD2
    True
    sage: HD.rels()
    ['b_1_1^2+b_1_0*b_1_1']

    sage: cS1 = HS.1*HS.2+HS.3; cS1
    (c_2_1)*(c_1_0)+(b_3_2): 3-Cocycle in H^*(Sym6; GF(2))
    sage: cS2 = HS.1*HS.2+HS.4; cS2
    (c_2_1)*(c_1_0)+(b_3_3): 3-Cocycle in H^*(Sym6; GF(2))
    sage: cS1*cS2 == HS.3*HS.4 + HS.1*HS.2*(HS.1*HS.2+HS.3+HS.4)
    True
    sage: HS.rels()
    ['b_3_2*b_3_3']

We define an embedding of `D` in `S` and compute the induced map from `HS` to `HD`:

    sage: emb = D.GroupHomomorphismByImages(S,D.GeneratorsOfGroup(),libgap.eval('[ (2,4), (1,2,3,4), (1,3)(2,4) ]'))
    sage: resS_D = HS.hom(emb,HD)
    sage: [resS_D(g).as_polynomial() for g in HS.gens()[1:]]
    ['b_1_0*b_1_1+b_1_0^2+c_2_2',
     'b_1_1+b_1_0',
     'c_2_2*b_1_1+c_2_2*b_1_0',
     'b_1_0^2*b_1_1+c_2_2*b_1_1']

Note that the generators of `HD` are `COCH`, while those of `HS` are `MODCOCH`. But the image of the induced map is formed by `MODCOCH`:

    sage: type(HD.1)
    <type 'pGroupCohomology.cochain.COCH'>
    sage: type(HS.1)
    <class 'pGroupCohomology.cochain.MODCOCH'>
    sage: type(resS_D(HS.1))
    <class 'pGroupCohomology.cochain.MODCOCH'>

It is possible to mix both classes in arithmetic expressions:

    sage: resS_D(HS.2) == HD.2+HD.3
    True
    sage: resS_D(HS.1)*resS_D(HS.2) == resS_D(HS.1)*HD.2+resS_D(HS.1)*HD.3
    True

class `pGroupCohomology.cochain.` `COCH`

  COCH extension class representing elements of cohomology rings.

  INPUT:

  - `H` – a cohomology ring (`COHO`)

  - `n` – the degree of the cochain (integer)

  - `s` – name of the \(n\)-cochain (string)

  - `M` – data describing the cochain. Either

      1. a \((1 \times d)\) `Matrix_gfpn_dense` matrix, or

      2. a \(d\)-tuple of integers

    where \(d\) is the projective rank of the \(n\)-th term of the resolution that underlies `H`

  - `ydeg` (optional, default `None`) – y-degree of the cochain

  - `rdeg` (optional, default `None`) – r-degree of the cochain

  OUTPUT:

  A degree \(n\) element of `H` of name s.

  NOTE:

  - Usually, a cochain will be created by doing algebra with the generators of a cohomology ring.

  - In our application (see `pGroupCohomology`), `rdeg==1` if and only if the cochain is a Duflot regular generator of a cohomology ring; `ydeg==1` if and only if the cochain is a generator of a cohomology ring that is neither nilpotent nor Duflot regular.

  - Every cochain is provided with a name. When a cochain is the result of a computation then its name will by default describe its construction. We think that this is a very useful feature.

  EXAMPLES:

  First, we show how one would usually create a cochain:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(8,3)
      sage: H.make()
      sage: C = H.2
      sage: D = H.3
      sage: C
      b_1_0: 1-Cocycle in H^*(D8; GF(2))
      sage: D
      b_1_1: 1-Cocycle in H^*(D8; GF(2))
      sage: C+D
      b_1_0+b_1_1: 1-Cocycle in H^*(D8; GF(2))
      sage: C*D
      (b_1_0)*(b_1_1): 2-Cocycle in H^*(D8; GF(2))
      sage: print(C^3)
      3-Cocycle in H^*(D8; GF(2)),
      represented by
      [1 0 0 0]
      sage: print(D^3)
      3-Cocycle in H^*(D8; GF(2)),
      represented by
      [0 1 0 0]

  Next, we show a non-commutative example. Just for documentation, we create the cochains more directly:

      sage: H = CohomologyRing(27,3, from_scratch=True)
      sage: print(H.resolution())
      Resolution:
      0 <- GF(3) <- GF(3)[E27]

  Incidentally, we know that the projective rank of the second term of the resolution is four. So, we can define:

      sage: from pGroupCohomology.cochain import COCH
      sage: C = COCH(H,2,'first',(1,0,1,2))

  Now, the resolution is computed out to the second term, and the cochain `C` has the name ‘first’:

      sage: print(H.resolution())
      Resolution:
      0 <- GF(3) <- GF(3)[E27] <- rank 2 <- rank 4
      sage: C
      first: 2-Cocycle  in H^*(E27; GF(3))
      sage: print(C)
      2-Cocycle in  H^*(E27; GF(3)),
      represented by
      [1 0 1 2]

  Using `Matrix_gfpn_dense` matrices, we provide a slightly different way to create a cochain. The matrix must be immutable:

      sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
      sage: D = COCH(H,2,'second', MTX(MatrixSpace(GF(3),1,4, implementation=MTX), [[0,1,0,1]], mutable=False))

  Now, we can add or subtract the cochains:

      sage: C+D
      first+second: 2-Cocycle in H^*(E27; GF(3))
      sage: print(C+D)
      2-Cocycle in H^*(E27; GF(3)),
      represented by
      [1 1 1 0]
      sage: print(C-D)
      2-Cocycle in H^*(E27; GF(3)),
      represented by
      [1 2 1 1]

  Scalar multiplication works as well:

      sage: 2*C
      2*(first): 2-Cocycle in H^*(E27; GF(3))
      sage: print(C*2)
      2-Cocycle in H^*(E27; GF(3)),
      represented by
      [2 0 2 1]

  But certainly, in cohomology computations the cup-product is the most interesting:

      sage: C*D
      (first)*(second): 4-Cocycle in H^*(E27; GF(3))
      sage: print(H.resolution())
      Resolution:
      0 <- GF(3) <- GF(3)[E27] <- rank 2 <- rank 4 <- rank 6 <- rank 7
      sage: E = C^2
      sage: E = C^2+D*C*2
      sage: E
      (first)**2+((second)*(first))*2: 4-Cocycle in H^*(E27; GF(3))
      sage: print(E)
      4-Cocycle in H^*(E27; GF(3)),
      represented by
      [2 2 0 1 0 0 2]

  Since \(p>2\) in this example, the cohomology ring is non-commutative:

      sage: X = COCH(H,3,'X',(1,1,1,0,0,0))
      sage: Y = COCH(H,3,'Y',(0,0,0,1,1,1))
      sage: print(X*Y)
      6-Cocycle in H^*(E27; GF(3)),
      represented by
      [2 1 1 0 0 0 0 0 0]
      sage: print(Y*X)
      6-Cocycle in H^*(E27; GF(3)),
      represented by
      [1 2 2 0 0 0 0 0 0]

  The name (which by default describes the construction of the cochain) can be overwritten:

      sage: E.name()
      '(first)**2+((second)*(first))*2'
      sage: E.setname('foo')
      sage: E
      foo: 4-Cocycle in H^*(E27; GF(3))

  `MTX`(*args, **kwds)

    COCH.MTX(self) -> Matrix_gfpn_dense

    Return the `Matrix_gfpn_dense` matrix by which `self` is defined.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: C = H.2*H.1
        sage: print(C.MTX())
        [0 0 1 0]

  `as_polynomial`()

    Return a string that represents `self` as a polynomial in its parent.

    NOTE:

    The name of `self` will be modified inplace

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: c = H.1*H.2+H.3^3
        sage: c
        (c_2_2)*(b_1_0)+(b_1_1)**3: 3-Cocycle in H^*(D8; GF(2))
        sage: c.setname('foo')
        sage: c
        foo: 3-Cocycle in H^*(D8; GF(2))
        sage: c.as_polynomial()
        'b_1_1^3+c_2_2*b_1_0'
        sage: c
        b_1_1^3+c_2_2*b_1_0: 3-Cocycle in H^*(D8; GF(2))

  `deg`()

    Return the degree of `self`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: C=H.2*H.1
        sage: C.deg()
        3

  `is_nilpotent`()

    Tells whether this cocycle is nilpotent.

    An elemenet of a mod-\(p\) cohomology ring of a finite group is nilpotent if and only if the restrictions to all maximal \(p\)-elementary abelian subgroups are.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace

    An example in even characteristic:

        sage: H = CohomologyRing(64,242)
        sage: H.make()
        sage: H.nil_radical()
        b_1_0*b_1_2+b_1_0^2,
        b_1_0*b_1_3+b_1_0*b_1_1+b_1_0^2
        sage: H('b_1_0*b_1_2+b_1_0^2').is_nilpotent()
        True
        sage: H('b_1_0*b_1_3+b_1_0*b_1_2').is_nilpotent()
        False
        sage: H('b_1_0*b_1_3+b_1_0*b_1_1+b_1_0^2').is_nilpotent()
        True

    An example in odd characteristic:

        sage: H = CohomologyRing(81,13)
        sage: H.make()
        sage: H.nil_radical()
        a_1_0,
        a_1_1,
        a_1_2,
        a_3_6,
        a_5_10
        sage: c = H('a_1_2*a_5_10')
        sage: bool(c)
        True
        sage: c.is_nilpotent()
        True
        sage: c.nilpotency_degree()
        2

    Two abelian examples, that gave a wrong answer with previous versions of the spkg:

        sage: H = CohomologyRing(3^4,gap.NumberSmallGroups(3^4))
        sage: H.make()
        sage: (H.5*H.6+H.7*H.8).is_nilpotent()
        True
        sage: (H.5*H.6+H.7*H.8).nilpotency_degree()
        3
        sage: H = CohomologyRing(16,2)
        sage: H.make()
        sage: H.3.is_nilpotent()
        True
        sage: H.3.nilpotency_degree()
        2

  `label`()

    COCH.name(self)

    Return the name of `self`.

    NOTE:

    When a `COCH` instance is created by invoking the init method, a name must be given. When further `COCH` instances are created by arithmetic operations, the name of the result describes its construction.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: C=H.2*H.1
        sage: print(C.name())
        (b_1_0)*(c_2_2)
        sage: H(C.name()) == C
        True

    Note that there is no automatic simplification when the result represents the trivial cochain:

        sage: (C*2).name()
        '((b_1_0)*(c_2_2))*0'
        sage: print(C*2)
        3-Cocycle in H^*(D8; GF(2)),
        represented by
        [0 0 0 0]

  `massey_power`(i=1)

    Return the \(p^i\)-fold restricted Massey product of `self`, or `None` if it does not exist.

    INPUT:

    `i` (optional integer, default 1)

    OUTPUT:

    A cochain with the same parent as `self`, named `"<%s; %d>"%(self.name(),i)`.

    NOTE:

    We refer to the \(p^i\)-fold restricted Massey product as the \(i\)-th restricted Massey power.

    According to [Kraines], for \(p > 2\), the 1st restricted Massey power of a cocycle \(C\) of odd degree in a cohomology ring with coefficients in \(\mathbb F_p\) is minus the Bockstein of the Steenrod \(p\)-th power, \(-\beta P^1(C)\).

    EXAMPLES:

    First, we study an example in the cohomology ring of an elementary abelian \(p\)-group. The cohomology ring is simple enough to allow for an explicit computation of Bockstein and Steenrod powers.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(9,2)
        sage: H.make()
        sage: H.gens()
        [1,
         c_2_1: 2-Cocycle in H^*(SmallGroup(9,2); GF(3)),
         c_2_2: 2-Cocycle in H^*(SmallGroup(9,2); GF(3)),
         a_1_0: 1-Cocycle in H^*(SmallGroup(9,2); GF(3)),
         a_1_1: 1-Cocycle in H^*(SmallGroup(9,2); GF(3))]

    We compute the 1st restricted Massey powers of the degree one generators. Of course, the degree two generators have no Massey power, as they are not nilpotent.

        sage: print(H.1.massey_power())
        None
        sage: H.element_as_polynomial(H.3.massey_power())
        -c_2_1: 2-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: H.element_as_polynomial(H.4.massey_power())
        -c_2_2: 2-Cocycle in H^*(SmallGroup(9,2); GF(3))

    Since indeed \(c_{2,1}\) and \(c_{2,2}\) are the Bocksteins of \(a_{1,0}\) and \(a_{1,1}\), Kraines’ formula is verified in degree one. But it also holds in degree three, as we are now going to show.

    We consider \(C = a_{1,0}c_{2,1}\). By Cartan formula and since \(P^0\) is the identity, we have \(P^1(C) = P^1(a_{1,0})c_{2,1} + a_{1,0}P(c_{2,1})\). Since \(P^1\) vanishes in degree one and acts as the \(p\)-th power in degree two, we get \(P^1(C) = a_{1,0}c_{2,1}^3\). Applying the Bockstein operator \(\beta\), we get \(\beta P^1(C) = c_{2,1}^4\), since \(\beta(c_{2,1}) = \beta^2(c_{1,0}) = 0\) and since \(\beta(xy)=\beta(x)y + (-1)^{\deg x}x\beta(y)\). Hence, according to Kraines, we should get \(\langle a_{1,0}c_{2,1}; 1\rangle = - c_{2,1}^4\). And indeed:

        sage: (H.1*H.3).massey_power()
        <(c_2_1)*(a_1_0); 1>: 8-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: H.element_as_polynomial(_)
        -c_2_1^4: 8-Cocycle in H^*(SmallGroup(9,2); GF(3))

    We now consider a more advanced example, namely the extraspecial 3-group of order 27 and exponent 3:

        sage: H = CohomologyRing(27,3)
        sage: H.make()

    We compute generators for the nil radical of `H` and compute the 3-fold Massey product for each generator that is of degree not more than 5:

        sage: singular(H).set_ring()
        sage: N = [H(str(X)) for X in H.nil_radical()]
        sage: MP = [X.massey_power() for X in N]
        sage: MP
        [<a_1_0; 1>: 2-Cocycle in H^*(E27; GF(3)),
         <a_1_1; 1>: 2-Cocycle in H^*(E27; GF(3)),
         <a_3_4; 1>: 8-Cocycle in H^*(E27; GF(3)),
         <a_3_5; 1>: 8-Cocycle in H^*(E27; GF(3))]

    After expressing them as polynomials in the cohomology generators, we obtain

        sage: [H.element_as_polynomial(X) for X in MP]
        [-b_2_0: 2-Cocycle in H^*(E27; GF(3)),
         -b_2_3: 2-Cocycle in H^*(E27; GF(3)),
         b_2_0^2*a_1_1*a_3_5+b_2_0^2*a_1_0*a_3_4+b_2_0*c_6_8: 8-Cocycle in H^*(E27; GF(3)),
         -b_2_0^3*b_2_2-b_2_0^2*a_1_1*a_3_5-b_2_0^2*a_1_0*a_3_5+b_2_3*c_6_8+b_2_0*c_6_8: 8-Cocycle in H^*(E27; GF(3))]

    Hence, particularly interesting seems to be the first restricted Massey power of the degree three generators of `H`. We take the restriction maps to the four classes of maximal elementary abelian subgroups, which are all of order 9:

        sage: r1 = H.restriction_maps()[2][1]
        sage: r1
        Induced homomorphism of degree 0 from H^*(E27; GF(3)) to H^*(SmallGroup(9,2); GF(3))
        sage: r2 = H.restriction_maps()[3][1]
        sage: r3 = H.restriction_maps()[4][1]
        sage: r4 = H.restriction_maps()[5][1]
        sage: C = H.8
        sage: C
        a_3_4: 3-Cocycle in H^*(E27; GF(3))
        sage: U = r1.codomain()
        sage: U.element_as_polynomial(r1(C))
        0: 3-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: U.element_as_polynomial(r2(C))
        -c_2_2*a_1_0+c_2_1*a_1_1: 3-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: U.element_as_polynomial(r3(C))
        -c_2_2*a_1_0+c_2_1*a_1_1: 3-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: U.element_as_polynomial(r4(C))
        c_2_2*a_1_1-c_2_2*a_1_0+c_2_1*a_1_1: 3-Cocycle in H^*(SmallGroup(9,2); GF(3))

    Hence, after computing Bockstein and Steenrod power in `U` as above, and since Steenrod power and Bockstein commute with restriction maps, the theorem of Kraines tells us that \(\langle C; 1\rangle\) should restrict to \(0\), \(c_{2,1}c_{2,2}^3 - c_{2,1}^3c_{2,2}\), \(c_{2,1}c_{2,2}^3 - c_{2,1}^3c_{2,2}\), and \(-c_{2,2}^4 - c_{2,1}c_{2,2}^3 + c_{2,1}^3c_{2,2}\). It does:

        sage: CP = C.massey_power()
        sage: U.element_as_polynomial(r1(CP))
        0: 8-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: U.element_as_polynomial(r2(CP))
        c_2_1*c_2_2^3-c_2_1^3*c_2_2: 8-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: U.element_as_polynomial(r3(CP))
        c_2_1*c_2_2^3-c_2_1^3*c_2_2: 8-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: U.element_as_polynomial(r4(CP))
        -c_2_2^4+c_2_1*c_2_2^3-c_2_1^3*c_2_2: 8-Cocycle in H^*(SmallGroup(9,2); GF(3))

    It is known that for this group, a cocycle is uniquely determined by its restrictions to the maximal elementary abelian subgroups. Hence, we have verified the computation of the first restricted Massey power of `C`.

    We don’t know of general results in the case of even characteristic. However, even in this case, we find that cocycles of higher degree can be produced by restricted Massey powers, for example for the cohomology ring of \(C_4\times C_4\):

        sage: H = CohomologyRing(16,2)
        sage: H.make()
        sage: x,a,b,c,d = H.gens()
        sage: c
        c_1_0: 1-Cocycle in H^*(SmallGroup(16,2); GF(2))
        sage: d
        c_1_1: 1-Cocycle in H^*(SmallGroup(16,2); GF(2))
        sage: H.element_as_polynomial(c.massey_power())
        0: 2-Cocycle in H^*(SmallGroup(16,2); GF(2))
        sage: H.element_as_polynomial(d.massey_power())
        0: 2-Cocycle in H^*(SmallGroup(16,2); GF(2))
        sage: H.element_as_polynomial(c.massey_power(2))
        c_2_1: 2-Cocycle in H^*(SmallGroup(16,2); GF(2))
        sage: H.element_as_polynomial(d.massey_power(2))
        c_2_2: 2-Cocycle in H^*(SmallGroup(16,2); GF(2))

    We verify that the result is consistent with the set-valued non-restricted Massey products:

        sage: sorted(list(H.massey_products(c,c,c,c)))
        [c_2_1: 2-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_2_1+c_1_0*c_1_1: 2-Cocycle in H^*(SmallGroup(16,2); GF(2))]
        sage: sorted(list(H.massey_products(d,d,d,d)))
        [c_2_2: 2-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_2_2+c_1_0*c_1_1: 2-Cocycle in H^*(SmallGroup(16,2); GF(2))]

  `name`()

    Return the name of `self`.

    NOTE:

    When a `COCH` instance is created by invoking the init method, a name must be given. When further `COCH` instances are created by arithmetic operations, the name of the result describes its construction.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: C=H.2*H.1
        sage: print(C.name())
        (b_1_0)*(c_2_2)
        sage: H(C.name()) == C
        True

    Note that there is no automatic simplification when the result represents the trivial cochain:

        sage: (C*2).name()
        '((b_1_0)*(c_2_2))*0'
        sage: print(C*2)
        3-Cocycle in H^*(D8; GF(2)),
        represented by
        [0 0 0 0]

  `nilpotency_degree`()

    The smallest exponent by which this cocycle becomes zero.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(64,18)
        sage: H.make()
        sage: H.nil_radical()
        a_1_0,
        a_1_1,
        a_2_0,
        a_2_1,
        a_5_5,
        a_5_8,
        a_6_7,
        a_6_10
        sage: c = H('a_5_5')
        sage: c.nilpotency_degree()
        4

    The following takes quite long, as it is needed to compute the resolution of this cohomology ring out to degree 20. However, it confirms the stated nilpotency degree:

        sage: bool(c^2), bool(c^3), bool(c^4)
        (True, True, False)

    If the cocycle is not nilpotent, infinity is returned:

        sage: c = H('b_2_3')
        sage: c.is_nilpotent()
        False
        sage: c.nilpotency_degree()
        +Infinity

    Of course, a zero cochain has nilpotency degree one:

        sage: (c*0).nilpotency_degree()
        1

  `normalize`()

    Scale `self` inplace so that its leading coefficient is 1 (if non-zero).

    OUTPUT:

    `True` if self is a null-cochain, and `None` otherwise

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(27,3)
        sage: H.make()
        sage: C=2*H.1+H.2
        sage: print(C)
        2-Cocycle in H^*(E27; GF(3)),
        represented by
        [2 1 0 0]
        sage: C.normalize()
        sage: print(C)
        2-Cocycle in H^*(E27; GF(3)),
        represented by
        [1 2 0 0]
        sage: C
        (2*(b_2_0)+b_2_1)/2: 2-Cocycle in H^*(E27; GF(3))
        sage: D = 0*H.2
        sage: D.normalize()
        True
        sage: D
        0*(b_2_1): 2-Cocycle in H^*(E27; GF(3))

  `rdeg`()

    Return the \(r\)-degree of `self`.

    NOTE:

    The r-degree plays an important role in the computation of cohomology rings. A generator of a cohomology ring has `rdeg==1` if and only if it is a Duflot regular generator, which means that its restriction to the greatest central elementary abelian subgroup is not nilpotent.

    EXAMPLES:

    The example produces files. For safety reasons, we choose files in a temporary directory; it will be removed as soon as Sage is quit:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: H.1.rdeg()
        1
        sage: H.2.rdeg()
        0
        sage: H.3.rdeg()
        0

  `resolution`()

    Return the underlying resolution.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3, from_scratch=True)
        sage: from pGroupCohomology.cochain import COCH
        sage: C=COCH(H,2,'foo',(1,1,0))

    Note that the needed terms of the resolution are automatically computed:

        sage: print(C.resolution())
        Resolution:
        0 <- GF(2) <- GF(2)[D8] <- rank 2 <- rank 3
        sage: C.resolution() is H.resolution()
        True

  `right_multiplication`()

    Return the cohomology ring endomorphism given by right-multiplication with `self`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: print(H)
        Cohomology ring of Dihedral group of order 8 with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [c_2_2: 2-Cocycle in H^*(D8; GF(2)),
         b_1_0: 1-Cocycle in H^*(D8; GF(2)),
         b_1_1: 1-Cocycle in H^*(D8; GF(2))]
        Minimal list of algebraic relations:
        [b_1_0*b_1_1]
        sage: x,a,b,c = H.gens()
        sage: B = b.right_multiplication()
        sage: C = c.right_multiplication()
        sage: B(a) == a*b
        True
        sage: A = a.right_multiplication()
        sage: BA = A(B)
        sage: BA(a) == a*a*b
        True
        sage: r = H.restriction_maps()[2][1]
        sage: rB = r(B)
        sage: r(a)*r(b) == rB(a)
        True

  `set_latex_name`(s)

    Declare how self should be typeset in LaTeX.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: latex(H.2)
        b_{1,0}
        sage: (H.2).set_latex_name('H_2')
        sage: latex(H.2)
        H_2

  `setname`(s, is_polyrep=False)

    Set the name of `self`.

    INPUT:

    s – a string providing the new name

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: C=H.2*H.1
        sage: C
        (b_1_0)*(c_2_2): 3-Cocycle in H^*(D8; GF(2))
        sage: C.setname('foo')
        sage: C
        foo: 3-Cocycle in H^*(D8; GF(2))

  `ydeg`()

    Return the \(y\)-degree of `self`.

    NOTE:

    The y-degree plays an important role in the computation of cohomology rings. A generator of a cohomology ring has `ydeg==1` if and only if it is nilpotent.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,3)
        sage: H.make()
        sage: print(H)
        Cohomology ring of Small Group number 3 of order 16 with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [b_2_1: 2-Cocycle in H^*(SmallGroup(16,3); GF(2)),
         c_2_2: 2-Cocycle in H^*(SmallGroup(16,3); GF(2)),
         c_2_3: 2-Cocycle in H^*(SmallGroup(16,3); GF(2)),
         a_1_0: 1-Cocycle in H^*(SmallGroup(16,3); GF(2)),
         b_1_1: 1-Cocycle in H^*(SmallGroup(16,3); GF(2))]
        Minimal list of algebraic relations:
        [a_1_0^2,
         a_1_0*b_1_1,
         b_2_1*a_1_0,
         b_2_1^2+c_2_2*b_1_1^2]
        sage: H.1.rdeg(),H.1.ydeg()
        (0, 0)
        sage: H.2.rdeg(),H.2.ydeg()
        (1, 0)
        sage: H.4.rdeg(),H.4.ydeg()
        (0, 1)

  `yoneda_cocycle`()

    Express `self` as a Yoneda cocycle.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: Y21 = H.2.yoneda_cocycle()*H.1.yoneda_cocycle()
        sage: X21 = (H.2*H.1).yoneda_cocycle()
        sage: Y21[0] == X21[0]
        True
        sage: Y21[1] == X21[1]
        True
        sage: Y21[2] == X21[2]
        True

class `pGroupCohomology.cochain.` `COCH_unpickle_class`

  Unpickling a cochain.

  EXAMPLES:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(8,3, from_scratch=True)
      sage: H.make()
      sage: C=H.2
      sage: type(C)
      <type 'pGroupCohomology.cochain.COCH'>
      sage: D = loads(dumps(C))   #indirect doctest
      sage: print(C)
      1-Cocycle in H^*(D8; GF(2)),
      represented by
      [1 0]
      rdeg = 0
      ydeg = 0
      sage: print(D)
      1-Cocycle in H^*(D8; GF(2)),
      represented by
      [1 0]
      rdeg = 0
      ydeg = 0

  `C` and `D` are different objects, but of course their parents are the same, and the cochains are equal:

      sage: D is C
      False
      sage: D.parent() is C.parent()
      True
      sage: D == C
      True

class `pGroupCohomology.cochain.` `ChMap`

  Extension class representing induced homomorphisms of cohomology rings.

  EXAMPLES:

  Usually, an induced homomorphism is created by defining two groups and a homomorphism between them, computing the cohomology rings of the groups, and then invoking the `hom`()` method of cohomology rings.

  We first create the cohomology rings for two different presentations of the dihedral group of order 8.

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: G1 = libgap.SmallGroup(8,3)
      sage: H1 = CohomologyRing(8,3, from_scratch=True)
      sage: H1.make()
      sage: G2 = libgap.DihedralGroup(8)
      sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
      sage: H2.make()

  In order to obtain reproducible doc tests, we switch to permutation groups that are, from the perspective of our programs, equivalent to `G1` and `G2`, and provide an explicit group isomorphism:

      sage: phi = libgap.eval('GroupHomomorphismByImages( Group( [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ] ), Group( [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ] ), [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ], [ (1,7)(2,8)(3,5)(4,6), (1,6)(2,5)(3,7)(4,8) ] )')
      sage: H1.group()==phi.Source()
      True
      sage: H2.group().canonicalIsomorphism(phi.Range())
      [ (1,2)(3,8)(4,6)(5,7), (1,3,4,7)(2,5,6,8) ] -> [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ]
      sage: phi.IsInjective()
      true
      sage: phi.IsSurjective()
      true

  After ensuring that `phi` is printed nicely, we obtain the induced map:

      sage: phi.SetName('phi')
      sage: phi_star = H2.hom(phi,H1)   #indirect doctest
      sage: phi_star
      phi^*
      sage: phi_star.domain()
      H^*(DihedralGroup(8); GF(2))
      sage: phi_star.codomain()
      H^*(D8; GF(2))
      sage: print([H1.element_as_polynomial(phi_star(X)) for X in H2.gens()])
      [1: 0-Cocycle in H^*(D8; GF(2)), b_1_0^2+c_2_2: 2-Cocycle in H^*(D8; GF(2)), b_1_1+b_1_0: 1-Cocycle in H^*(D8; GF(2)), b_1_0: 1-Cocycle in H^*(D8; GF(2))]

  Similarly, we get the induced map of the inverse map:

      sage: Src = phi.Source()
      sage: Rng = phi.Range()
      sage: Gens = Rng.GeneratorsOfGroup()
      sage: phi_inv = Rng.GroupHomomorphismByImages(Src, Gens, [phi.PreImagesRepresentative(g) for g in Gens])
      sage: phi_star_inv = H1.hom(phi_inv,H2)
      sage: print([H2.element_as_polynomial(phi_star_inv(X)) for X in H1.gens()])
      [1: 0-Cocycle in H^*(DihedralGroup(8); GF(2)), b_1_0*b_1_1+c_2_2: 2-Cocycle in H^*(DihedralGroup(8); GF(2)), b_1_1: 1-Cocycle in H^*(DihedralGroup(8); GF(2)), b_1_1+b_1_0: 1-Cocycle in H^*(DihedralGroup(8); GF(2))]

  One can compose induced maps by multiplication respectively by applying one map to the other. Here, we test that the composition of the induced map and its inverse is the identity:

      sage: [X == phi_star_inv(phi_star(X)) == (phi_star_inv*phi_star)(X) == phi_star_inv(phi_star)(X) for X in H2.gens()]
      [True, True, True, True]
      sage: [X == phi_star(phi_star_inv(X)) == (phi_star*phi_star_inv)(X) == phi_star(phi_star_inv)(X) for X in H1.gens()]
      [True, True, True, True]

  It is possible to convert an induced homomorphism into a map of quotient rings in the Singular interface. This allows for working with cohomology ring elements of very high degrees. However, it is always needed to take care of the `basering` in Singular:

      sage: S_phi_star = singular(phi_star)
      sage: singular(H2).set_ring()
      sage: I = singular.ideal(['c_2_2^50','b_1_0^50','b_1_1^50'])
      sage: singular(H1).set_ring()
      sage: imI = S_phi_star(I)

  Note that Singular does pfte not do automatic reduction in quotient rings. So, eventually we do the reductions explicitly, in two ways, with the same result:

      sage: imI.reduce(singular('ideal(0)'))
      b_1_0^100+c_2_2^2*b_1_0^96+c_2_2^16*b_1_0^68+c_2_2^18*b_1_0^64+c_2_2^32*b_1_0^36+c_2_2^34*b_1_0^32+c_2_2^48*b_1_0^4+c_2_2^50,
      b_1_1^50+b_1_0^50,
      b_1_0^50
      sage: singular(H2).set_ring()
      sage: I_red = I.reduce(singular('ideal(0)'))
      sage: singular(H1).set_ring()
      sage: S_phi_star(I_red).reduce(singular('ideal(0)'))
      b_1_0^100+c_2_2^2*b_1_0^96+c_2_2^16*b_1_0^68+c_2_2^18*b_1_0^64+c_2_2^32*b_1_0^36+c_2_2^34*b_1_0^32+c_2_2^48*b_1_0^4+c_2_2^50,
      b_1_1^50+b_1_0^50,
      b_1_0^50

  `G_map`()

    Return the underlying homomorphism of group algebras (given by a `Matrix_gfpn_dense` matrix).

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: G2 = libgap.DihedralGroup(8)
        sage: H1 = CohomologyRing(8,3)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H1.make()
        sage: H2.make()

    In order to obtain reproducible doc tests, we switch to permutation groups that are, from the perspective of our programs, equivalent to `G1` and `G2`, and provide an explicit group isomorphism:

        sage: phi = libgap.eval('GroupHomomorphismByImages( Group( [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ] ), Group( [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ] ), [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ], [ (1,7)(2,8)(3,5)(4,6), (1,6)(2,5)(3,7)(4,8) ] )')
        sage: H1.group()==phi.Source()
        True
        sage: H2.group().canonicalIsomorphism(phi.Range()) != libgap.eval('fail')
        True
        sage: phi.IsInjective()
        true
        sage: phi.IsSurjective()
        true
        sage: phi_star = H2.hom(phi,H1)
        sage: print(phi_star.G_map())
        [1 0 0 0 0 0 0 0]
        [0 1 1 1 1 1 1 1]
        [0 1 0 0 1 1 0 0]
        [0 0 0 1 0 0 1 1]
        [0 0 0 1 1 0 0 1]
        [0 0 0 0 0 1 1 0]
        [0 0 0 0 0 1 0 1]
        [0 0 0 0 0 0 0 1]

  `apply_to_chain`(d, C)

    Apply the underlying chain map of `self` to a \(d\)-chain.

    INPUT:

    - `d`, the degree of the chain

    - `C`, a \((r\times |G|)\) `Matrix_gfpn_dense` matrix, where \(r\) is the rank of the \(d\)-th term of the resolution, and \(|G|\) is the group order.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: f = H.2.right_multiplication()
        sage: print(f.apply_to_chain(1, MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[0,1,0,1,0,1,0,1],[1,0,1,0,1,0,1,0]])))
        [0 1 0 1 0 1 0 1]

  `deg`()

    Return the degree of `self`.

    NOTE:

    An induced homomorphism always is of degree zero. We provide this method since `ChMap` in principle also works for more general maps so that the image has a different degree from the source.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = G1.IsomorphismGroups(G2)
        sage: phi_star = H2.hom(phi,H1)
        sage: phi_star.deg()
        0

  `exportData`(f)

    Store data describing the induced map into files.

    INPUT:

    `f` - a string, providing the path and the beginning of the name of the files into which the terms of `self` shall be saved

    OUTPUT:

    The matrix `self[i]` is saved to the file `f+repr(i)`.

    NOTE:

    This method is internally used, in order to save memory by disposing of data that are currently not needed. So, a user would normally not directly invoke the method.

    TESTS:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H1 = CohomologyRing(8,3)
        sage: H1.make()
        sage: G = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = libgap.eval('GroupHomomorphismByImages( Group( [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ] ), Group( [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ] ), [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ], [ (1,7)(2,8)(3,5)(4,6), (1,6)(2,5)(3,7)(4,8) ] )')
        sage: phi_star = H2.hom(phi,H1)
        sage: print(phi_star(H2.1))
        2-Cocycle in H^*(D8; GF(2)),
        represented by
        [1 0 1]
        sage: print(phi_star.__getitem_name__(1))
        [1 0 0 0 0 0 0 0]
        [1 1 1 1 1 1 0 0]
        [1 0 0 0 0 0 0 0]
        [0 0 1 1 0 0 0 0]
        sage: f = tmp_dir()
        sage: phi_star.exportData(f)
        sage: phi_star.__getitem_name__(1) == f+'1'
        True

  `kernel`()

    Compute the kernel.

    TEST:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(81,8)
        sage: H.make()
        sage: H.restriction_maps()[2][1].kernel()
        a_1_1,
        a_2_1,
        a_2_2,
        a_3_2,
        b_4_2-a_4_1,
        a_5_3+a_5_2,
        b_6_3-a_1_0*a_5_2,
        a_7_5+b_2_0*a_5_2+c_6_4*a_1_0
        sage: H.restriction_maps()[2][1]( H('b_6_3-a_1_0*a_5_2') )
        (b_6_3-((a_1_0)*(a_5_2)))_: 6-Cocycle in H^*(SmallGroup(9,2); GF(3))
        sage: _.MTX()
        [0 0 0 0 0 0 0]

  `knownDeg`()

    Return the degree out to which `self` was constructed.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()

    In order to obtain reproducible doc tests, we switch to permutation groups that are, from the perspective of our programs, equivalent to `G1` and `G2`, and provide an explicit group isomorphism:

        sage: phi = libgap.eval('GroupHomomorphismByImages( Group( [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ] ), Group( [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ] ), [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ], [ (1,7)(2,8)(3,5)(4,6), (1,6)(2,5)(3,7)(4,8) ] )')
        sage: H1.group()==phi.Source()
        True
        sage: H2.group().canonicalIsomorphism(phi.Range()) != libgap.eval('fail')
        True
        sage: phi.IsInjective()
        true
        sage: phi.IsSurjective()
        true
        sage: phi_star = H2.hom(phi,H1)
        sage: phi_star.knownDeg()
        0
        sage: print(phi_star(H2.1))
        2-Cocycle in H^*(D8; GF(2)),
        represented by
        [1 0 1]
        sage: phi_star.knownDeg()
        2

  `label`()

    Provide a short description of this chain map, using a name when available.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H1 = CohomologyRing(8,3)
        sage: H1.make()
        sage: G = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = libgap.eval('GroupHomomorphismByImages( Group( [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ] ), Group( [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ] ), [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ], [ (1,7)(2,8)(3,5)(4,6), (1,6)(2,5)(3,7)(4,8) ] )')
        sage: phi_star = H2.hom(phi,H1)
        sage: phi_star.label()
        'Map H^*(DihedralGroup_8_; GF(2)) -> H^*(8gp3; GF(2))'
        sage: phi_star.set_name('phi^*')
        sage: phi_star.label()
        'phi^*'

  `lift`()

    Compute the next unknown term of `self`.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()

    In order to obtain reproducible doc tests, we switch to permutation groups that are, from the perspective of our programs, equivalent to `G1` and `G2`, and provide an explicit group isomorphism:

        sage: phi = libgap.eval('GroupHomomorphismByImages( Group( [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ] ), Group( [ (1,5)(2,6)(3,8)(4,7), (1,3,2,4)(5,7,6,8) ] ), [ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ], [ (1,7)(2,8)(3,5)(4,6), (1,6)(2,5)(3,7)(4,8) ] )')
        sage: H1.group()==phi.Source()
        True
        sage: H2.group().canonicalIsomorphism(phi.Range()) != libgap.eval('fail')
        True
        sage: phi.IsInjective()
        true
        sage: phi.IsSurjective()
        true
        sage: phi_star = H2.hom(phi,H1)
        sage: phi_star.lift()
        sage: phi_star.knownDeg()
        1
        sage: phi_star[1]
        [1 0 0 0 0 0 0 0]
        [1 1 1 1 1 1 0 0]
        [1 0 0 0 0 0 0 0]
        [0 0 1 1 0 0 0 0]

  `name`()

    Return the name of `self`.

    NOTE:

    Since induced homomorphisms are cached, there can not be two equal induced homomorphisms with a different name.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = G1.IsomorphismGroups(G2)
        sage: phi.SetName('phi')
        sage: phi_star = H2.hom(phi,H1)
        sage: phi_star.name()
        'phi^*'

  `poincare_of_image`()

    Poincaré series of the image of `self` (which is a sub-ring of the codomain of `self`).

    THEORY:

    The kernel of self is computed, using Singular. Together with the relation ideal of the domain of self, it allows to compute the Poincaré series of the quotient of the domain by the kernel, which is isomorphic to the image of self.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()

    We study the restriction to one maximal elementary abelian subgroup:

        sage: phi = H.restriction_maps()[2][1]
        sage: phi
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))
        sage: [phi.codomain().element_as_polynomial(phi(X)) for X in H.gens()]
        [1: 0-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         c_1_0*c_1_1+c_1_0^2: 2-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         c_1_1: 1-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         0: 1-Cocycle in H^*(SmallGroup(4,2); GF(2))]

    Apparently, the image has dimension one in degree one (given by `c_1_1`) and dimension two in degree two (given by `c_1_1^2` and `c_1_0*c_1_1+c_1_0^2`). And this can be verified using the Poincaré series of the image:

        sage: phi.poincare_of_image()
        1/(t^3 - t^2 - t + 1)
        sage: R.<t> = PowerSeriesRing(QQ)
        sage: (1/(t^3 - t^2 - t + 1))[1]
        1
        sage: (1/(t^3 - t^2 - t + 1))[2]
        2

    SEE ALSO:

    `rank_of_image()`

  `preimage`(Item=None, Id=None)

    ASSUMPTION:

    `self.codomain()` is completely computed.

    INPUT:

    - `Item` – (optional) element in `singular(self.codomain())`

        or element of `self.codomain()`.

    - `Id` – (optional) ideal (given by a list of strings) in the codomain, so that lift of `Item` will be done modulo that ideal. Only available if `Item` is not provided as an element of `self.codomain()` but as element in Singular.

    OUTPUT:

    Return the preimage of `Item` in `singular(self.domain())`, if `self.domain()` is completely known, and in the current basering of `self.domain()` otherwise.

    - If `Item` is not provided, the kernel of `self` resp. the preimage of the ideal given by `Id` is returned as an ideal in `singular(self.codomain())`.

    - If `Item` is a single element and `Id` is `None`, a representative of the preimage of `Item` is returned, or `None` if there is no preimage.

    - If `Item` is a single element and `Id` defines an ideal, a pair is returned, namely one element of the preimage (or `None`, if there is no preimage) and the preimage of the ideal given by `Id`).

    ALGORITHM:

    According to chapter 4.3 of [Green].

    EXAMPLE:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,3)
        sage: H.make()
        sage: r = H.restriction_maps()[1][1]
        sage: r
        Induced homomorphism of degree 0 from H^*(SmallGroup(16,3); GF(2)) to H^*(SmallGroup(4,2); GF(2))
        sage: singular(r.codomain()).set_ring()
        sage: p = singular((r.codomain().1+r.codomain().2)^2); p
        c_1_1^2+c_1_0^2
        sage: I = singular.maxideal(2); I
        c_1_1^2,
        c_1_0*c_1_1,
        c_1_0^2
        sage: singular(H).set_ring()
        sage: r.preimage()
        a_1_0,
        b_1_1,
        b_2_1
        sage: r.preimage(p)
        (c_2_3+c_2_2, a_1_0,
        b_1_1,
        b_2_1)
        sage: r.preimage(Id=I)
        a_1_0,
        b_1_1,
        c_2_2,
        c_2_3,
        b_2_1

    If both an element and an ideal are provided, one preimage of the preimage of the coset ‘element + ideal’ is returned, together with the preimage of the ideal. Here, the preimage of `p` found above is contained in the preimage of the ideal `I`:

        sage: r.preimage(p,Id=I)
        (0, a_1_0,
        b_1_1,
        c_2_2,
        c_2_3,
        b_2_1)

    We verify these findings. The kernel:

        sage: [r(H(t)).as_polynomial() for t in ['a_1_0','b_1_1','b_2_1']]
        ['0', '0', '0']

    The preimage of `I`:

        sage: [r(H(t)).as_polynomial() for t in ['a_1_0','b_1_1','c_2_2','c_2_3','b_2_1']]
        ['0', '0', 'c_1_1^2', 'c_1_0^2', '0']

    The preimage of `p`:

        sage: r(H('c_2_3+c_2_2')).as_polynomial()
        'c_1_1^2+c_1_0^2'

  `rank_of_image`(d)

    Rank of the image of term number \(d\) of `self`.

    THEORY:

    The rank of the image is computed by applying some linear algebra to the `d`-th term of self.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()

    We study the restriction to one maximal elementary abelian subgroup:

        sage: phi = H.restriction_maps()[2][1]
        sage: phi
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))
        sage: [phi.codomain().element_as_polynomial(phi(X)) for X in H.gens()]
        [1: 0-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         c_1_0*c_1_1+c_1_0^2: 2-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         c_1_1: 1-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         0: 1-Cocycle in H^*(SmallGroup(4,2); GF(2))]

    Apparently, the image has dimension one in degree one (given by `c_1_1`) and dimension two in degree two (given by `c_1_1^2` and `c_1_0*c_1_1+c_1_0^2`). And this can be verified using the Poincaré series of the image:

        sage: phi.rank_of_image(1)
        1
        sage: phi.rank_of_image(2)
        2

    SEE ALSO:

    `poincare_of_image()`

  `set_name`(s)

    Give `self` a name.

    NOTE:

    Since induced homomorphisms are cached, there can not be two equal induced homomorphisms with a different name. If the `hom()` method is called, the name will be reset.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = G1.IsomorphismGroups(G2)
        sage: phi.SetName('phi')
        sage: phi_star = H2.hom(phi,H1)
        sage: phi_star.name()
        'phi^*'
        sage: phi_star.set_name('foobar')
        sage: phi_star.name()
        'foobar'
        sage: H2.hom(phi,H1).name()
        'phi^*'
        sage: phi_star.name()
        'phi^*'

  `src`()

    Return the source of the underlying chain map (type `RESL`).

    NOTE:

    Since cohomology is a contravariant functor, the output of `src()` is the resolution of the codomain.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = G1.IsomorphismGroups(G2)
        sage: phi_star = H2.hom(phi,H1)
        sage: print(phi_star.src())
        Resolution:
        0 <- GF(2) <- GF(2)[D8] <- rank 2 <- rank 3 <- rank 4
        sage: phi_star.src() is phi_star.codomain().resolution()
        True

  `tgt`()

    Return the codomain of the underlying chain map (type `RESL`).

    NOTE:

    Since cohomology is a contravariant functor, the output of `tgt()` is the resolution of the domain.

    EXAMPLES:

    We first create the cohomology rings for two different presentations of the dihedral group of order 8.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G1 = libgap.SmallGroup(8,3)
        sage: H1 = CohomologyRing(8,3, from_scratch=True)
        sage: H1.make()
        sage: G2 = libgap.DihedralGroup(8)
        sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H2.make()
        sage: phi = G1.IsomorphismGroups(G2)
        sage: phi_star = H2.hom(phi,H1)
        sage: print(phi_star.tgt())
        Resolution:
        0 <- GF(2) <- GF(2)[DihedralGroup(8)] <- rank 2 <- rank 3 <- rank 4
        sage: phi_star.tgt() is phi_star.domain().resolution()
        True

class `pGroupCohomology.cochain.` `ChMap_unpickle_class`

  Unpickling an instance of `ChMap`, representing an induced homomorphism.

  EXAMPLES:

  Usually, an induced homomorphism is created by defining two groups and a homomorphism between them, computing the cohomology rings of the groups, and then invoking the `hom()` method of cohomology rings.

  We first create the cohomology rings for two different presentations of the dihedral group of order 8.

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: G1 = libgap.SmallGroup(8,3)
      sage: H1 = CohomologyRing(8,3, from_scratch=True)
      sage: H1.make()
      sage: G2 = libgap.DihedralGroup(8)
      sage: H2 = CohomologyRing(G2, GroupName = 'DihedralGroup(8)', from_scratch=True)
      sage: H2.make()
      sage: phi = G1.IsomorphismGroups(G2)

  After ensuring that `phi` is printed nicely, we obtain the induced map and see that it is cached:

      sage: phi.SetName('phi')
      sage: phi_star = H2.hom(phi,H1)
      sage: phi_star is loads(dumps(phi_star))   # indirect doctest
      True

class `pGroupCohomology.cochain.` `CohomologyHomset`(X, Y, category=None)

  Set of Homomorphisms between Modular Cohomology Rings of Finite \(p\)-Groups.

  EXAMPLES:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace

  We consider the dihedral group of order 8 and will study the restriction maps to representatives for all conjugacy classes of non-trivial subgroups.

      sage: G = libgap.DihedralGroup(8)
      sage: H = CohomologyRing(G,GroupName = 'D8', from_scratch=True)
      sage: H.make()
      sage: SubG = [X.RepresentativeSmallest() for X in G.ConjugacyClassesSubgroups()]
      sage: SubG = [X.MinimalGeneratingSet().Group() for X in SubG if X.Order()>1]
      sage: for i in range(len(SubG)):
      ....:     SubG[i].SetName('U%d'%(i+1))
      sage: HSubG = [CohomologyRing(X, from_scratch=True) for X in SubG]
      sage: for X in HSubG:
      ....:     X.make()
      sage: IncG = [X.GroupHomomorphismByImages(G,X.GeneratorsOfGroup(),X.GeneratorsOfGroup()) for X in SubG]
      sage: for i in range(len(IncG)):
      ....:     IncG[i].SetName('i_%d'%(i+1))
      sage: ResG = [H.hom(IncG[i], HSubG[i]) for i in range(len(HSubG))]   # indirect doctest

  Now, we can apply the maps to elements of `H`:

      sage: ResG[2](H.2+H.3)
      i_3^*(b_1_0+b_1_1): 1-Cocycle in H^*(SmallGroup(2,1); GF(2))

  The image of an element of the base field is mapped to itself, while cochains of degree 0 are properly mapped:

      sage: ResG[2](H.0)
      1
      sage: ResG[2](H(1))
      i_3^*(1): 0-Cocycle in H^*(SmallGroup(2,1); GF(2))

  Finally, we show how the images of non-scalar generators of `H` under the various restrictions maps can be expressed as elements of the cohomology rings of the subgroups:

      sage: for f in ResG:
      ....:     print([f.codomain().element_as_polynomial(f(X)).name() for X in H.gens()[1:]])
      ['c_1_0^2', '0', '0']
      ['0', 'c_1_0', '0']
      ['c_1_0^2', 'c_1_0', 'c_1_0']
      ['c_1_1^2+c_1_0*c_1_1', 'c_1_0', '0']
      ['c_2_0', '0', 'c_1_0']
      ['c_1_1^2+c_1_0*c_1_1+c_1_0^2', 'c_1_1', 'c_1_1']
      ['c_2_2', 'b_1_0', 'b_1_1']

class `pGroupCohomology.cochain.` `MODCOCH`(parent, value, deg=None, name=None, S=None, rdeg=None, ydeg=None, is_polyrep=False, is_NF=None)

  Elements of modular cohomology rings of finite groups.

  See `pGroupCohomology` or `MODCOHO` for examples of cohomology computations.

  EXAMPLES:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(720,763,prime=2)
      sage: H.make()
      sage: H.2
      c_1_0: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))
      sage: print(H('b_3_3*c_3_2+c_2_1^2*c_1_0^2'))   #indirect doctest
      (b_3_3)*(c_3_2)+(((c_2_1)^2)*((c_1_0)^2)): 6-Cocycle in H^*(SmallGroup(720,763); GF(2))
      defined by
      b_1_1^4*c_1_2^2+b_1_0^4*c_1_2^2+c_2_5*b_1_0^3*c_1_2+c_2_5^2*b_1_1^2+c_2_5^2*b_1_0*c_1_2+b_1_1^2*c_1_2^4+c_2_5^2*c_1_2^2

  `as_cocycle_in_subgroup`()

    Represent `self` as stable cocycle of the chosen subgroup.

    OUTPUT:

    The element (`MODCOCH`) of `self.parent().subgroup_cohomology()` by which `self` is defined.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G = libgap.AlternatingGroup(8)
        sage: H = CohomologyRing(G,prime=2,GroupName='A8') # long time
        sage: H.make()              # long time
        sage: H.subgroup_cohomology()
        H^*(SmallGroup(192,1493); GF(2))
        sage: H.1.as_cocycle_in_subgroup()
        (b_1_0)^2+(b_2_2)+(b_2_1): 2-Cocycle in H^*(SmallGroup(192,1493); GF(2))
        sage: H.subgroup_cohomology()('b_1_0^2+b_2_2+b_2_1')*H.2.as_cocycle_in_subgroup() == (H.1*H.2).as_cocycle_in_subgroup()
        True

  `as_cocycle_in_sylow`()

    Represent `self` as stable cocycle of the Sylow subgroup.

    OUTPUT:

    The element (`MODCOCH`) of `self.parent().sylow_cohomology()` that corresponds to `self`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: G = libgap.AlternatingGroup(8)
        sage: H = CohomologyRing(G,prime=2,GroupName='A8')  # long time
        sage: H.make()                          # long time
        sage: H.1.as_cocycle_in_sylow()
        b_1_1*b_1_2+b_1_1^2+b_1_0^2+b_2_5+b_2_4: 2-Cocycle in H^*(SmallGroup(64,138); GF(2))
        sage: H.sylow_cohomology()('b_1_1*b_1_2+b_1_1^2+b_1_0^2+b_2_5+b_2_4')*H.2.as_cocycle_in_sylow() == (H.1*H.2).as_cocycle_in_sylow()
        True

  `as_polynomial`()

    Find a polynomial representation of `self`.

    OUTPUT: A string that defines a polynomial, expressed in the given generator names of the cohomology ring

    NOTE: The name of the cohomology ring element will be changed into the polynomial expression.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: c = H.2
        sage: c.setname('charly')
        sage: c
        charly: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))
        sage: c.name()
        'charly'
        sage: c.as_polynomial()
        'c_1_0'
        sage: c
        c_1_0: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))

  `coef`(m)

    The coefficient of a monomial.

    INPUT:

    `m`: A monomial of the underlying cohomology ring of a subgroup (String or Singular

    OUTPUT:

    `self` can be considered as a stable element of the cohomology of a subgroup. Return the coefficient of `m` in the normal form of that stable element.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(400,206,prime=5)
        sage: H.make()
        sage: c = H.2*H.3*H.1
        sage: print(c)
        ((c_8_0)*(c_16_1))*(a_6_0): 30-Cocycle in H^*(SmallGroup(400,206); GF(5))
        defined by
        c_2_1^3*c_2_2^11*a_1_0*a_1_1-c_2_1^11*c_2_2^3*a_1_0*a_1_1

    We can use a monomial in the Singular interface

        sage: c.coef(c.lm())
        1

    or given by a string:

        sage: c.coef('c_2_1^11*c_2_2^3*a_1_0*a_1_1')
        -1

  `coef_list`(M)

    Return the list of coefficients.

    INPUT:

    A list of standard monomials (represented by strings) of the cohomology ring of the underlying subgroup

    OUTPUT:

    A list of integers, providing the coefficients of the given monomials in the stable element (normal form) that corresponds to `self`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(400,206,prime=5)
        sage: H.make()
        sage: c = H.2*H.3*H.1
        sage: print(c)
        ((c_8_0)*(c_16_1))*(a_6_0): 30-Cocycle in H^*(SmallGroup(400,206); GF(5))
        defined by
        c_2_1^3*c_2_2^11*a_1_0*a_1_1-c_2_1^11*c_2_2^3*a_1_0*a_1_1

    We wish to get the list of coefficients of `c` for all standard monomials of the underlying subgroup:

        sage: M = H.subgroup_cohomology().standard_monomials(30); M
        ['c_2_2^14*a_1_0*a_1_1', 'c_2_1*c_2_2^13*a_1_0*a_1_1', 'c_2_1^2*c_2_2^12*a_1_0*a_1_1', 'c_2_1^3*c_2_2^11*a_1_0*a_1_1', 'c_2_1^4*c_2_2^10*a_1_0*a_1_1', 'c_2_1^5*c_2_2^9*a_1_0*a_1_1', 'c_2_1^6*c_2_2^8*a_1_0*a_1_1', 'c_2_1^7*c_2_2^7*a_1_0*a_1_1', 'c_2_1^8*c_2_2^6*a_1_0*a_1_1', 'c_2_1^9*c_2_2^5*a_1_0*a_1_1', 'c_2_1^10*c_2_2^4*a_1_0*a_1_1', 'c_2_1^11*c_2_2^3*a_1_0*a_1_1', 'c_2_1^12*c_2_2^2*a_1_0*a_1_1', 'c_2_1^13*c_2_2*a_1_0*a_1_1', 'c_2_1^14*a_1_0*a_1_1', 'c_2_2^15', 'c_2_1*c_2_2^14', 'c_2_1^2*c_2_2^13', 'c_2_1^3*c_2_2^12', 'c_2_1^4*c_2_2^11', 'c_2_1^5*c_2_2^10', 'c_2_1^6*c_2_2^9', 'c_2_1^7*c_2_2^8', 'c_2_1^8*c_2_2^7', 'c_2_1^9*c_2_2^6', 'c_2_1^10*c_2_2^5', 'c_2_1^11*c_2_2^4', 'c_2_1^12*c_2_2^3', 'c_2_1^13*c_2_2^2', 'c_2_1^14*c_2_2', 'c_2_1^15']
        sage: c.coef_list(M)
        [0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

  `deg`()

    Degree of a cohomology element.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: H('c_3_2^2+b_3_3*c_3_2+c_2_1*c_1_0*c_3_2').deg()
        6

    The degree may be explicitly provided in the definition of the cohomology ring element, even if it is not clear from its given value:

        sage: from pGroupCohomology.cochain import MODCOCH
        sage: c = MODCOCH(H, '0', deg=15)
        sage: c.deg()
        15

  `is_nilpotent`()

    Tells whether this cocycle is nilpotent.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(60,3,prime=2)
        sage: H.make()
        sage: singular(H).set_ring()
        sage: H.nil_radical()
        c_1_0
        sage: H.gens()
        [1,
         c_2_0: 2-Cocycle in H^*(SmallGroup(60,3); GF(2)),
         c_1_0: 1-Cocycle in H^*(SmallGroup(60,3); GF(2))]
        sage: H.gen(1).is_nilpotent()
        False
        sage: H.gen(2).is_nilpotent()
        True
        sage: bool(H.gen(2)^2)
        False

    An example in odd characteristic:

        sage: H = CohomologyRing(1620, 23, prime=3)
        sage: H.make()
        sage: H.1.is_nilpotent()
        True
        sage: bool(H.1^2)
        True
        sage: bool(H.1^3)
        False
        sage: H.2.is_nilpotent()
        False

  `lc`()

    Leading coefficient of `self` (type <int>).

    OUTPUT:

    An element of a modular cohomology ring of a finite group is given by a stable element in the cohomology ring of a suitable subgroup. Expressing the stable element as a polynomial, this method returns its leading coefficient, as an int.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(400,206,prime=5)
        sage: H.make()
        sage: singular(H.subgroup_cohomology()).set_ring()
        sage: (H.6*H.8).lc()
        2

  `lm`()

    Leading monomial (no coefficient) of `self`.

    OUTPUT:

    An element of a modular cohomology ring of a finite group is given by a stable element in the cohomology ring of a suitable subgroup. Expressing the stable element as a polynomial, this method returns its leading monomial, as an element of the Singular interface.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(72,40,prime=3)
        sage: H.make()
        sage: singular(H.subgroup_cohomology()).set_ring()
        sage: H.4.lm()
        c_2_1*c_2_2^2*a_1_0

  `lm_string`()

    Leading monomial (no coefficient) of `self` (type <string>).

    OUTPUT:

    An element of a modular cohomology ring of a finite group is given by a stable element in the cohomology ring of a suitable subgroup. Expressing the stable element as a polynomial, this method returns its leading monomial, as a string.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(72,40,prime=3)
        sage: H.make()
        sage: H.4.lm_string()
        'c_2_1*c_2_2^2*a_1_0'

  `lt`()

    Leading term of the underlying cohomology element.

    OUTPUT:

    An element of a modular cohomology ring of a finite group is given by a stable element in the cohomology ring of a suitable subgroup. Expressing the stable element as a polynomial, this method returns its leading term (i.e., the product of coefficient and monomial), as an element in the Singular interface.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(400,206,prime=5)
        sage: H.make()
        sage: singular(H.subgroup_cohomology()).set_ring()
        sage: (H.6*H.8).lt()
        2*c_2_1^5*c_2_2^5*a_1_0*a_1_1

  `massey_power`(i=1)

    Experimental: Restricted Massey power.

    ALGORITHM:

    A cocycle `C` is expressed as a (stable) element of the cohomology of the Sylow subgroup. The Massey power is computed there (see `massey_power()`).

    NOTE:

    We did not prove that the result always is a stable element. But if it is, it yields the restricted Massey power of `C`. Therefore, this method is merely experimental.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(432,234,prime=3)
        sage: H.make()
        sage: c = H.5; c
        a_3_0: 3-Cocycle in H^*(SmallGroup(432,234); GF(3))
        sage: cS = c.as_cocycle_in_sylow(); cS
        b_2_3*a_1_1+b_2_0*a_1_0: 3-Cocycle in H^*(E27; GF(3))
        sage: cM = c.massey_power(); cM
        b_4_0*b_4_1+b_4_0^2: 8-Cocycle in H^*(SmallGroup(432,234); GF(3))
        sage: cSM = cS.massey_power(); cSM
        <(b_2_3)*(a_1_1)+(b_2_0)*(a_1_0); 1>: 8-Cocycle in H^*(E27; GF(3))
        sage: cM.as_cocycle_in_sylow() == cSM
        True

  `name`()

    Return the name of the cohomology ring element.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: c = H.2
        sage: c.name()
        'c_1_0'
        sage: c.setname('charly')
        sage: c
        charly: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))
        sage: c.name()
        'charly'
        sage: c.as_polynomial()
        'c_1_0'
        sage: c
        c_1_0: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))

  `nilpotency_degree`()

    The smallest exponent by which this cocycle becomes zero.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(60,3,prime=2)
        sage: H.make()
        sage: singular(H).set_ring()
        sage: H.nil_radical()
        c_1_0
        sage: H.gens()
        [1,
         c_2_0: 2-Cocycle in H^*(SmallGroup(60,3); GF(2)),
         c_1_0: 1-Cocycle in H^*(SmallGroup(60,3); GF(2))]
        sage: H.1.is_nilpotent()
        False
        sage: H.1.nilpotency_degree()
        +Infinity
        sage: (H.1*0).nilpotency_degree()
        1
        sage: H.2.is_nilpotent()
        True
        sage: bool(H.2^2)
        False
        sage: H.2.nilpotency_degree()
        2

    An example in odd characteristic:

        sage: H = CohomologyRing(1620, 23, prime=3)
        sage: H.make()
        sage: for g in H.Gen:
        ....:     if g.nilpotency_degree() == 3:
        ....:         break
        ....:
        sage: bool(g^2)
        True
        sage: bool(g^3)
        False
        sage: H.2.is_nilpotent()
        False
        sage: H.2.nilpotency_degree()
        +Infinity
        sage: (H.2*0).nilpotency_degree()
        1

  `nilreduce`()

    Inplace reduction of `self`’s value by the ideal generated by nilpotent generators.

    OUTPUT:

    `self`. Before, all nilpotent generators of the cohomology containing `self.value()` are killed in `self.value()`.

    EXAMPLES:

    Since this test relies on the ring presentation of the cohomology of a certain subgroup, we compute it from scratch, rather than relying on potentially outdated data in the local sources.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: X = CohomologyRing(81,8, from_scratch=True)
        sage: X.make()
        sage: H = CohomologyRing(648,132,prime=3, from_scratch=True)
        sage: H.make()
        sage: c = copy(H.5)
        sage: c
        c_6_0: 6-Cocycle in H^*(SmallGroup(648,132); GF(3))

    `c` is a regular element (marked by the letter ‘c’ in its name). We took a copy of the generator of `H` since `c` will be changed inplace. Interpreted as an element of the cohomology of the underlying subgroup, it has one nilpotent summand:

        sage: c.as_cocycle_in_subgroup()
        b_6_3+a_1_0*a_5_2-c_6_4: 6-Cocycle in H^*(SmallGroup(81,8); GF(3))

    We kill this summand:

        sage: c.nilreduce()
        c_6_0: 6-Cocycle in H^*(SmallGroup(648,132); GF(3))
        sage: c.as_cocycle_in_subgroup()
        b_6_3-c_6_4: 6-Cocycle in H^*(SmallGroup(81,8); GF(3))

    Indeed, the value of `c` has changed:

        sage: c == H.5
        False

  `rdeg`()

    \(r\)-degree.

    This is supposed to be 1 for Duflot elements, i.e., for those elements that have a non-zero restrictions to the centre of a Sylow subgroup.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: [t.rdeg() for t in H.Gen]
        [1, 1, 0, 1]

    So, the restriction of all but the third generator to the centre of a Sylow subgroup should be non-zero:

        sage: r = H.restriction_maps()[1][1]
        sage: r
        Induced homomorphism of degree 0 from H^*(SmallGroup(720,763); GF(2)) to H^*(SmallGroup(4,2); GF(2))
        sage: print(r(H.1)._NF_())
        c_1_1^2: 2-Cocycle in H^*(SmallGroup(4,2); GF(2))
        defined by
        c_1_1^2
        sage: print(r(H.2)._NF_())
        c_1_0: 1-Cocycle in H^*(SmallGroup(4,2); GF(2))
        defined by
        c_1_0
        sage: print(r(H.3)._NF_())
        0: 3-Cocycle in H^*(SmallGroup(4,2); GF(2))
        defined by
        0
        sage: print(r(H.4)._NF_())
        c_1_0*c_1_1^2: 3-Cocycle in H^*(SmallGroup(4,2); GF(2))
        defined by
        c_1_0*c_1_1^2

  `set_latex_name`(s)

    Declare how self should be typeset in LaTeX.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: latex(H.2)
        b_{1,0}
        sage: (H.2).set_latex_name('H_2')
        sage: latex(H.2)
        H_2

  `setname`(s, is_polyrep=False)

    Set the name of a cohomology ring element.

    INPUT:

    - `s` (string), new namme of the element

    - `is_polyrep` (optional boolean, default `False`): If `True`, the user asserts that the new name provides a polynomial representation of the element, expressed in the given generator names of the cohomology ring

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: c = H.2
        sage: c.setname('charly')
        sage: c
        charly: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))
        sage: c.name()
        'charly'
        sage: c.as_polynomial()
        'c_1_0'
        sage: c
        c_1_0: 1-Cocycle in H^*(SmallGroup(720,763); GF(2))

  `val_str`()

    A polynomial representation as stable element.

    OUTPUT:

    A string that provides a polynomial representation for the cohomology ring element, expressed as a (stable) cocycle of the underlying subgroup.

    NOTE:

    In general, the normal form is not computed before returning the result.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: (H.1*H.2)._NF_().val_str()
        'b_1_1^2*c_1_2+b_1_0^2*c_1_2+c_2_5*b_1_1+b_1_1*c_1_2^2+c_2_5*c_1_2'
        sage: H.one().val_str()
        '1'

  `value`()

    The value of self in the Singular interface.

    NOTE:

    By “value”, we mean its representation in the Singular interface as a stable element in the cohomology ring of the chosen subgroup.

    This value is not unique, as the cohomology ring of the subgroup is a quotient ring. Thus, the value is a coset representative, and it is not necessarily in normal form.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2)
        sage: H.make()
        sage: singular(H.subgroup_cohomology()).set_ring()
        sage: (H.1*H.2+H.3)._NF_().value()
        b_1_1^2*c_1_2+b_1_0^2*c_1_2+c_2_5*b_1_1+c_2_5*b_1_0+b_1_1*c_1_2^2+c_2_5*c_1_2

    Note that if Singular crashed, it is attempted to reconstructed the value. However, this is only possible if `val_str()` was called before.

        sage: c = (H.1*H.2+H.3)._NF_()
        sage: c.val_str()
        'b_1_1^2*c_1_2+b_1_0^2*c_1_2+c_2_5*b_1_1+c_2_5*b_1_0+b_1_1*c_1_2^2+c_2_5*c_1_2'
        sage: singular.quit()
        sage: CohomologyRing.global_options('info')
        sage: c.value()
        H^*(D8xC2; GF(2)):
            Reconstructing data in the Singular interface
        b_1_1^2*c_1_2+b_1_0^2*c_1_2+c_2_5*b_1_1+c_2_5*b_1_0+b_1_1*c_1_2^2+c_2_5*c_1_2
        sage: CohomologyRing.global_options('warn')

  `ydeg`()

    \(y\)-degree.

    This is supposed to be 1 for nilpotent elements.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=3)
        sage: H.make()
        sage: [t.ydeg() for t in H.Gen]
        [0, 0, 1, 1]

    Indeed, the last two generators are nilpotent:

        sage: print(H.3**2)
        (a_3_0)^2: 6-Cocycle in H^*(SmallGroup(720,763); GF(3))
        defined by
        0
        sage: print(H.4**2)
        (a_7_1)^2: 14-Cocycle in H^*(SmallGroup(720,763); GF(3))
        defined by
        0

`pGroupCohomology.cochain.` `MODCOCH_unpickle`(L0, L1, L2, L3, L4, L5, L6=False, L7=None)

  Auxiliary function for unpickling `MODCOCH`.

  TESTS:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(720,763,prime=2)
      sage: H.make()
      sage: H.1 == loads(dumps(H.1)) #indirect doctest
      True
      sage: H.1 is loads(dumps(H.1)) #indirect doctest
      False

class `pGroupCohomology.cochain.` `YCOCH`

  Yoneda cochains.

  This is an auxiliary class to facilitate the computation of Massey products.

  A Yoneda \(i\)-cochain is a collection of maps from the \((i+n)\)-the term to the \(n\)-th term of a resolution of a group algebra, \(n=0,1,2,...\). There is no compatibility condition whatsoever (e.g., the maps are not supposed to commute with the boundary maps of the resolution).

  Yoneda cochains form a cocomplex, equipped with the coboundary map \(\partial\) defined by \((\partial \phi^i)_n = \phi_n\circ d_{n+i+1} - (-1)^i d_{n-i+1}\circ \phi_{n+1}^i\) where

  - \(P_\ast\) is a resolution

  - \(\phi^i\) is a Yoneda \(i\)-cochain, \(\phi^i_n: P_{i+n}\to P_n\) for \(n=0,1,2,...\)

  - \(\phi_n\\circ d_{n+i+1}\) means \(d_{n+i+1}\) followed by \(\phi_n\).

  If \(Y_1,Y_2\) are two Yoneda cochains, then \(Y_1*Y_2\) is their composition, where we use the convention first \(Y_2\) then \(Y_1\).

  INPUT:

  - `R`: a resolution (`RESL`)

  - `n`: the degree of the Yoneda cochain (non-negative integer)

  - `M_0,M_1,...,M_i,...`: a list of `Matrix_gfpn_dense` matrices defining maps from the \((n+i)\)-th to the \(i\)-th term of `R`.

  - `coboundary=None` (optional): If it is given, it must be a Yoneda cocycle that is the coboundary of self

  - `construction=None` (optional): If it is given, it is a list describing its construction. Either:

    > - `['+',Y1,Y2]` (self is sum of Yoneda cochains `Y1, Y2`),

    > - `['-',Y1,Y2]` (self is `Y1-Y2`),

    > - `['-',Y]` (self is `-Y`),

    > - `['*',Y1,Y2]` (self is the composition of two Yoneda cochains, `Y2` followed by `Y1`), or

    > - `['D',Y]` (self is the coboundary of the Yoneda cochain `Y`).

  NOTE:

  The optional parameters are internally used in `coboundary()`, `find_cobounding_yoneda_cochains()` and when adding or composing Yoneda cochains. We however document some of the options here.

  We did not implement comparisons between Yoneda cochains, simply since they morally have infinitely many terms, and if two Yoneda cochains have a different construction, it would thus hardly be possible to prove equality, in general.

  EXAMPLES:

      sage: from pGroupCohomology import CohomologyRing
      sage: from pGroupCohomology.cochain import YCOCH
      sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(8,3)
      sage: H.make()
      sage: R = H.resolution()
      sage: R
      Resolution of GF(2)[D8]
      sage: Y = YCOCH(R,1, MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,0,1,0,1,0,1,0],[1,0,1,0,1,0,1,0]]))
      sage: len(Y)
      1

  If higher terms of `Y` are required, they are automatically computed. Since no construction and no coboundary was provided in the definition of `Y`, it is lifted so that its coboundary is zero.

      sage: Y[1]
      [1 0 0 0 0 0 0 0]
      [0 1 0 0 0 1 0 0]
      [0 0 0 0 0 0 0 0]
      [1 0 0 1 0 0 0 0]
      [0 0 0 0 1 0 0 0]
      [0 0 0 1 0 1 0 0]
      sage: len(Y)
      2
      sage: Y[0]
      [1 0 1 0 1 0 1 0]
      [1 0 1 0 1 0 1 0]
      sage: Y.coboundary()[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]

  Next, we provide all terms explicitly, yielding a Yoneda cochain that is not a cocycle:

      sage: tmpM1 = MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,0,1,0,1,0,1,0],[1,0,1,0,1,0,1,0]])
      sage: tmpM2 = MTX(MatrixSpace(GF(2),6,8, implementation=MTX), [[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0]])
      sage: Y = YCOCH(R,1,tmpM1,tmpM2)
      sage: Y
      Yoneda 1-cochain on a resolution of GF(2)[D8]
      sage: Y[0]
      [1 0 1 0 1 0 1 0]
      [1 0 1 0 1 0 1 0]
      sage: Y[1]
      [0 1 1 0 0 1 1 0]
      [1 1 0 0 1 1 0 0]
      [1 0 1 0 1 0 1 0]
      [0 1 1 0 0 1 1 0]
      [1 1 0 0 1 1 0 0]
      [1 0 1 0 1 0 1 0]
      sage: Y.coboundary()[0]
      [0 1 1 1 0 0 0 1]
      [0 1 1 1 1 1 1 0]
      [0 1 1 0 0 0 1 1]
      sage: Y.coboundary()[1]
      [0 0 0 0 1 0 0 0]
      [0 1 0 0 0 0 0 0]
      [0 0 1 0 0 0 0 0]
      [0 0 0 1 0 1 0 0]
      [0 0 0 0 0 0 0 0]
      [0 1 0 0 0 0 0 0]
      [0 0 1 0 0 0 0 0]
      [0 0 0 0 0 1 0 0]

  Of course, the coboundary of the coboundary vanishes:

      sage: Y.coboundary().coboundary()[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 0 0 0 0 0 0]
      sage: Y.coboundary().coboundary()[1]
      [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 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 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]

  Here is what happens internally when defining the composition of `Y` with itself:

      sage: YY = YCOCH(R, 2, construction=['*',Y,Y])
      sage: YY[0]
      [1 0 0 0 0 0 1 1]
      [1 1 1 0 1 1 1 1]
      [0 1 1 0 1 1 0 0]
      sage: YY[1]
      [0 1 0 0 0 0 0 0]
      [0 1 0 0 1 0 0 1]
      [1 1 1 1 1 1 1 1]
      [1 0 0 0 1 0 0 0]
      [0 1 1 1 1 1 0 1]
      [1 0 0 0 1 1 1 0]
      [0 1 0 1 0 0 1 0]
      [1 1 0 1 0 0 1 0]

  However, usually one would define the composition like that:

      sage: YY = Y*Y
      sage: YY[0]
      [1 0 0 0 0 0 1 1]
      [1 1 1 0 1 1 1 1]
      [0 1 1 0 1 1 0 0]
      sage: YY[1]
      [0 1 0 0 0 0 0 0]
      [0 1 0 0 1 0 0 1]
      [1 1 1 1 1 1 1 1]
      [1 0 0 0 1 0 0 0]
      [0 1 1 1 1 1 0 1]
      [1 0 0 0 1 1 1 0]
      [0 1 0 1 0 0 1 0]
      [1 1 0 1 0 0 1 0]

  Internally, the coboundary of `YY` would be constructed like that:

      sage: DYY = YCOCH(YY.resolution(), YY.deg()+1, construction=['D',YY])
      sage: DYY[0]
      [0 1 0 0 1 0 0 1]
      [0 1 0 0 0 1 1 0]
      [0 0 1 1 1 1 1 1]
      [0 0 1 1 1 1 0 1]
      sage: DYY[1]
      [0 0 0 0 0 0 0 0]
      [0 0 0 0 0 0 0 0]
      [0 0 1 1 0 0 1 1]
      [0 0 1 0 0 0 1 0]
      [0 0 0 1 1 0 1 0]
      [0 1 1 0 0 1 1 0]
      [0 1 0 1 0 0 1 0]
      [0 0 1 1 1 0 1 1]
      [0 1 0 1 0 0 1 0]
      [0 0 1 0 1 0 1 1]

  Of course, for the user it is easier to just do

      sage: DYY = YY.coboundary()
      sage: DYY[0]
      [0 1 0 0 1 0 0 1]
      [0 1 0 0 0 1 1 0]
      [0 0 1 1 1 1 1 1]
      [0 0 1 1 1 1 0 1]

  `append`(M)

    append further terms to `self`.

    INPUT:

    `M`: `Matrix_gfpn_dense` matrix defining the next term of self

    NOTE:

    Actually an immutable copy of `M` is appended.

    Warning: It is strongly recommended to not use this method manually, as it is not checked whether the appended term fits to the construction of the Yoneda cochain.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
        sage: from pGroupCohomology.cochain import YCOCH
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: tmpM1 = MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,0,1,0,1,0,1,0],[1,0,1,0,1,0,1,0]])
        sage: tmpM2 = MTX(MatrixSpace(GF(2),6,8, implementation=MTX), [[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0]])
        sage: Y = YCOCH(H.resolution(), 1, tmpM1, tmpM2)
        sage: M = MTX(MatrixSpace(GF(2),12,8, implementation=MTX), [[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0]])
        sage: Y.append(M)
        sage: Y[2]==M
        True

  `coboundary`()

    Return the Yoneda coboundary of `self`.

    THEORY:

    If \(d_\ast: P_\ast \to P_{\ast-1}\) denotes the boundary maps of \(P_\ast\) and \(\phi^i\) is a Yoneda \(i\)-cochain with \(\phi^i_n: P_{i+n}\to P_n\) then \((\partial \phi^i)_n = \phi_n\circ d_{n+i+1} - (-1)^i d_{n-i+1}\circ \phi_{n+1}^i\), which is a Yoneda \((i+1)\)-cocycle.

    NOTE:

    Coboundary and lifting commute, see `lift()`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
        sage: from pGroupCohomology.cochain import YCOCH
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: tmpM1 = MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,0,1,0,1,0,1,0],[1,0,1,0,1,0,1,0]])
        sage: tmpM2 = MTX(MatrixSpace(GF(2),6,8, implementation=MTX), [[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0]])
        sage: Y = YCOCH(H.resolution(),1,tmpM1, tmpM2)
        sage: YC = Y.coboundary()
        sage: YC
        Yoneda 2-cochain on a resolution of GF(2)[D8]
        sage: print(YC[0])
        [0 1 1 1 0 0 0 1]
        [0 1 1 1 1 1 1 0]
        [0 1 1 0 0 0 1 1]
        sage: print(YC[1])
        [0 0 0 0 1 0 0 0]
        [0 1 0 0 0 0 0 0]
        [0 0 1 0 0 0 0 0]
        [0 0 0 1 0 1 0 0]
        [0 0 0 0 0 0 0 0]
        [0 1 0 0 0 0 0 0]
        [0 0 1 0 0 0 0 0]
        [0 0 0 0 0 1 0 0]
        sage: print(YC[2])
        [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 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 1 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 1 1 0 0 0 0 0]

    The coboundary of the coboundary vanishes:

        sage: YCC = YC.coboundary()
        sage: print(YCC[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 0 0 0 0 0 0]
        sage: print(YCC[1])
        [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 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 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]

  `deg`()

    Return the degree of `self`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: from pGroupCohomology.cochain import YCOCH
        sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: Y = YCOCH(H.resolution(),2,H.resolution().CochainToChainmap(2,H.1.MTX())[2])
        sage: Y.deg()
        2

  `find_cobounding_yoneda_cochains`(all=True)

    Construct Yoneda cochains whose coboundary is `self`.

    ASSUMPTION:

    `self` is a Yoneda cocycle. Note that this assumption is not verified.

    OUTPUT:

    A list of Yoneda cochains whose coboundary is `self`.

    If the optional parameter `all` is `True` (which is default) then a list of Yoneda cochains is returned that are pairwise not cohomologous (i.e., the pairwise difference is not a coboundary). Otherwise, the list will only contain at most one Yoneda cochain.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: H.gens()
        [1,
         c_2_2: 2-Cocycle in H^*(D8; GF(2)),
         b_1_0: 1-Cocycle in H^*(D8; GF(2)),
         b_1_1: 1-Cocycle in H^*(D8; GF(2))]
        sage: H.rels()
        ['b_1_0*b_1_1']
        sage: Y1 = H.2.yoneda_cocycle()
        sage: Y2 = H.3.yoneda_cocycle()
        sage: Y12 = Y1*Y2
        sage: Y12.find_cobounding_yoneda_cochains()
        [Yoneda 1-cochain on a resolution of GF(2)[D8],
         Yoneda 1-cochain on a resolution of GF(2)[D8],
         Yoneda 1-cochain on a resolution of GF(2)[D8],
         Yoneda 1-cochain on a resolution of GF(2)[D8]]
        sage: C1, C2, C3, C4 = _

    Indeed, the pairwise differences are no coboundaries:

        sage: print(C1[0])
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        sage: print(C2[0])
        [1 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        sage: print(C3[0])
        [0 0 0 0 0 0 0 0]
        [1 0 0 0 0 0 0 0]
        sage: print(C4[0])
        [1 0 0 0 0 0 0 0]
        [1 0 0 0 0 0 0 0]

    But the coboundary of `C1,...,C4` is `Y12`:

        sage: print(C1.coboundary()[1])
        [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 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 0 0]
        [0 0 0 1 0 0 0 0]
        sage: Y12[1] == C1.coboundary()[1]
        True
        sage: Y12[0] == C1.coboundary()[0]
        True
        sage: Y12[1] == C1.coboundary()[1]
        True
        sage: Y12[2] == C1.coboundary()[2]
        True
        sage: Y12[0] == C2.coboundary()[0]
        True
        sage: Y12[1] == C2.coboundary()[1]
        True
        sage: Y12[2] == C2.coboundary()[2]
        True
        sage: Y12[0] == C3.coboundary()[0]
        True
        sage: Y12[1] == C3.coboundary()[1]
        True
        sage: Y12[2] == C3.coboundary()[2]
        True
        sage: Y12[0] == C4.coboundary()[0]
        True
        sage: Y12[1] == C4.coboundary()[1]
        True
        sage: Y12[2] == C4.coboundary()[2]
        True

  `lift`(check=False)

    Compute the next term of `self`.

    THEORY:

    If the coboundary of self vanishes, then the next term is chosen so that the coboundary still vanishes. In the general case, since the coboundary of a Yoneda cochain is a cocycle, we can lift the coboundary according to the previously stated property. Then, the next term is chosen such that the lift and the coboundary map commute.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
        sage: from pGroupCohomology.cochain import YCOCH
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: tmpM1 = MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,0,1,0,1,0,1,0],[1,0,1,0,1,0,1,0]])
        sage: tmpM2 = MTX(MatrixSpace(GF(2),6,8, implementation=MTX), [[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0],[0,1,1,0,0,1,1,0],[1,1,0,0,1,1,0,0],[1,0,1,0,1,0,1,0]])
        sage: Y = YCOCH(H.resolution(), 1, tmpM1, tmpM2)
        sage: YC = Y.coboundary()
        sage: len(YC)
        1

    We compute the third term of `YC` and verify that this is the same as computing the fourth term of `Y` and then taking the third term of the coboundary of the extended version of `Y`. Note that when asking for a term that has not been computed yet (e.g., `YC[2]`) then lifting is done automatically.

        sage: print(YC[2])
        [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 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 1 1 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 0 0 0 0 0 0 0]
        [0 1 1 0 0 0 0 0]
        sage: Y.lift()
        sage: Y.lift()
        sage: len(Y)
        4

    Now, as four terms of `Y` are known, the third term of its coboundary is known even without lifting. But it coincides with the third term obtained by lifting `YC`:

        sage: YC[2] == Y.coboundary()[2]
        True

  `resolution`()

    Return the resolution over which `self` is defined.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: from pGroupCohomology.cochain import YCOCH
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.make()
        sage: Y = YCOCH(H.resolution(),2,H.resolution().CochainToChainmap(2,H.1.MTX())[2])
        sage: print(Y.resolution())
        Resolution:
        0 <- GF(2) <- GF(2)[D8] <- rank 2 <- rank 3 <- rank 4