Basic cohomology code for groups of prime power order — "p_group_cohomology" 3.3.2 documentation

# Basic cohomology code for groups of prime power order

This module contains `COHO`, that provides a framework for the computation of the cohomology rings with coefficients in \(\mathbb F_p\) for any finite \(p\)-group. It is based on algorithms of David Green and Dave Benson. See `pGroupCohomology` for an extensive introduction. Note that `MODCOHO`, the basic class for the non prime power case, inherits from `COHO`, so that many methods of the former work in the non prime power case as well.

AUTHORS:

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

class `pGroupCohomology.cohomology.` `COHO`(*args, **kwds)

  Modular Cohomology Rings of Finite \(p\)-Groups with coefficients in \(\mathbb F_p\).

  AUTHORS:

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

  INPUT:

  A finite \(p\)-group, either given by its coordinates in the SmallGroups library of Hans Ulrich Besche, Bettina Eick and Eamonn O’Brien, or given as a group in the libgap interface.

  OUTPUT:

  An object set up to compute the cohomology ring of the given \(p\)-group with coefficients in \(\mathbb F_p\).

  ALGORITHM:

  The methods are based on algorithms due to Dave Benson, David Green, Simon King and Peter Symonds.

  Eventually, a minimal generating set for the cohomology ring and a minimal set of algebraic relations is computed, together with various other information (e.g., Poincaré series).

  By `global_options()` and by various parameters (see below), it can be influenced by what methods the results are computed, how the computation is documented, and where files created during the computation are stored.

  The purpose of this examples is to document some internals of the implementation. For examples of the actual use of this package, we refer to `pGroupCohomology`. Note that usually one would not construct an instance of the class COHO directly. Just for documentation, we use COHO in all but the first example. In the first example, we use the constructor `pGroupCohomology.CohomologyRing()`, which is the recommended way of creating a cohomology ring.

  EXAMPLES:

  First, a small example with logging enabled. We use the constructor `pGroupCohomology.CohomologyRing()` in a way that prevents the ring from being downloaded from the web repository or reloaded from the data based shipped with this package.

  When setting up the cohomology ring, the cohomology of various elementary abelian subgroups is computed first. But if they’d happen to be found in the local sources, they would simply be loaded from there. In order to make the doctest independent of the contents of this database, we compute the two rings in question separately and insist on a computation from scratch. For one of them, we show details of the computation by logging:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: tmp_root = tmp_dir()
      sage: CohomologyRing.set_workspace(tmp_root)
      sage: X = CohomologyRing(4,2, from_scratch=True)
      sage: X.make()
      sage: X = CohomologyRing(2,1, from_scratch=True, options='info')
      _get_p_group_from_scratch:
          We compute this cohomology ring from scratch
      H^*(SmallGroup(2,1); GF(2)):
          Initialising maximal p-elementary abelian subgroups
      sage: X.make()
      Resolution of GF(2)[SmallGroup(2,1)]:
          Computing next term
          > rk P_02 =   1
      H^*(SmallGroup(2,1); GF(2)):
          We have to choose 1 new generator in degree 1
          > There is 1 Duflot regular generator in degree 1
          Summary: 0 relations and 1 generators in degree 1
          Ring approximation computed out to degree 1!
          Storing approximation data
          Determine degree 2 standard monomials
          We got 1 standard monomials
          There is no new generator in degree 2
          Summary: 0 relations and 0 generators in degree 2
          Ring approximation computed out to degree 2!
          Storing approximation data

  Since the group of order two is abelian, it is known a priori that the cohomology ring can be presented in degree at most two. So, we don’t need to use any complicated completeness criterion. Now, for the dihedral group of order 8. This package contains a list of custom names for some groups from the SmallGroups library, and the dihedral group is part of that list.

  Note that we don’t need to give the argument `options='info'` again, since this option is already in use.

      sage: H = CohomologyRing(8,3, from_scratch=True)
      _get_p_group_from_scratch:
          We compute this cohomology ring from scratch
          Computing basic setup for Small Group number 3 of order 8
      H^*(D8; GF(2)):
          Initialising maximal p-elementary abelian subgroups
          Inserting SmallGroup(2,1) as a subgroup
          ...
          Computing Dickson invariants in elementary abelian subgroup of rank 2

  Now, the basic setup is done. We compute the ring structure, logging the computation:

      sage: H
      H^*(D8; GF(2))
      sage: H.make()
          Compute group_is_abelian
          We have no degree bound yet
          Start computation in Degree 1
      Resolution of GF(2)[D8]:
          Make degree 1 autolift data
      H^*(D8; GF(2)):
          There are new generators, we have to lift the restriction maps
      Resolution of GF(2)[D8]:
          Computing next term
          > rk P_02 =   3
      Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(2,1); GF(2)):
          lift in the source resolution
          lift in the target resolution to degree 1
      Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
          lift in the source resolution
          lift in the target resolution to degree 1
      Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
          lift in the source resolution
          lift in the target resolution to degree 1
      H^*(D8; GF(2)):
          We have to choose 2 new generators in degree 1
          > There are 0 nilpotent generators in degree 1
          > There are 2 "boring" generators in degree 1
          Summary: 0 relations and 2 generators in degree 1
          Try to lift 1st power of 0th Dickson invariant
          Simultaneously lifting subgroup cochains of degree 1
          Simultaneous lift was successful!
          Factorising an element; it can be interrupted with Ctrl-c
          Ring approximation computed out to degree 1!
          Storing approximation data
          We expect a relation in degree at least 2
          Start computation in Degree 2
          Determine degree 2 standard monomials
          We got 3 standard monomials
          There are new generators, we have to lift the restriction maps
      Resolution of GF(2)[D8]:
          Computing next term
          > rk P_03 =   4
      Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(2,1); GF(2)):
          lift in the source resolution
          lift in the target resolution to degree 2
      Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
          lift in the source resolution
          lift in the target resolution to degree 2
      Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
          lift in the source resolution
          lift in the target resolution to degree 2
      H^*(D8; GF(2)):
          We have to choose 1 new generator in degree 2
          > There are 0 nilpotent generators in degree 2
          > There are 0 "boring" generators in degree 2
          > There is 1 Duflot regular generator in degree 2
          Summary: 1 relations and 1 generators in degree 2
          Ring approximation computed out to degree 2!
          Storing approximation data
          Compute dependent_parameters
          Try to find a set of generators over which the cohomology ring is finite.
          Computing complete Groebner basis
      H^*(SmallGroup(4,2); GF(2)):
          Computing complete Groebner basis
      H^*(D8; GF(2)):
          Trying Symonds' criterion
          Successful application of the Symonds criterion
          Finished computation of the ring structure
          Storing approximation data
      sage: CohomologyRing.global_options('warn')
      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]

  Now, without logging, an example using a group defined in Gap. This time, just for documentation, we invoke the class COHO directly (but in practice, one should of course use `CohomologyRing()`).

      sage: from pGroupCohomology.cohomology import COHO
      sage: CohomologyRing.global_options('warn')
      sage: G = libgap.DihedralGroup(8)
      sage: G
      <pc group of size 8 with 3 generators>
      sage: G.SetName("OtherName")
      <BLANKLINE>
      sage: G
      OtherName
      sage: H2 = COHO(G,root=tmp_root)
      sage: H2
      H^*(OtherName; GF(2))
      sage: H2.make()
      sage: print(H2)
      Cohomology ring of OtherName with coefficients in GF(2)
      <BLANKLINE>
      Computation complete
      Minimal list of generators:
      [c_2_2: 2-Cocycle in H^*(OtherName; GF(2)),
       b_1_0: 1-Cocycle in H^*(OtherName; GF(2)),
       b_1_1: 1-Cocycle in H^*(OtherName; GF(2))]
      Minimal list of algebraic relations:
      [b_1_0*b_1_1+b_1_0^2]

  Next, a slightly bigger example:

      sage: H4 = COHO(64,14,root=tmp_root)
      sage: H4.make()    # about 20 seconds
      sage: H4.gens()
      [1,
       a_2_1: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_2_2: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_4_4: 4-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_0: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_1: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_3_3: 3-Cocycle in H^*(SmallGroup(64,14); GF(2))]

  It depends on the python version whether or not the relations are tail-reduced and how they are sorted:

      sage: if (2, 8) < sys.version_info:
      ....:     expected_rels = ['a_1_0^2', 'a_1_0*a_1_1', 'a_1_1^3', 'a_2_1*a_1_0',
      ....:           'a_2_1^2+a_2_1*a_1_1^2', 'a_1_0*a_3_3+a_2_1*a_1_1^2',
      ....:           'a_1_1*a_3_3+a_2_1*a_1_1^2', 'a_2_1*a_3_3', 'a_3_3^2']
      ....: else:
      ....:     expected_rels = ['a_1_0^2', 'a_1_0*a_1_1', 'a_1_1^3', 'a_2_1*a_1_0',
      ....:           'a_2_1^2+a_2_1*a_1_1^2', 'a_1_1*a_3_3+a_2_1^2',
      ....:           'a_1_0*a_3_3+a_2_1^2', 'a_2_1*a_3_3', 'a_3_3^2']
      ....:
      sage: H4.rels() == expected_rels
      True

  An example with \(p=3\), so that the cohomology ring is non-commutative:

      sage: R = COHO(27,3,root=tmp_root)
      sage: R.make()
      sage: R.gens()
      [1,
       b_2_0: 2-Cocycle in H^*(E27; GF(3)),
       b_2_1: 2-Cocycle in H^*(E27; GF(3)),
       b_2_2: 2-Cocycle in H^*(E27; GF(3)),
       b_2_3: 2-Cocycle in H^*(E27; GF(3)),
       c_6_8: 6-Cocycle in H^*(E27; GF(3)),
       a_1_0: 1-Cocycle in H^*(E27; GF(3)),
       a_1_1: 1-Cocycle in H^*(E27; GF(3)),
       a_3_4: 3-Cocycle in H^*(E27; GF(3)),
       a_3_5: 3-Cocycle in H^*(E27; GF(3))]
      sage: print(R('a_1_0*a_3_4'))
      4-Cocycle in H^*(E27; GF(3)),
      represented by
      [1 0 0 0 0 0 0]
      sage: print(R('a_3_4*a_1_0'))
      4-Cocycle in H^*(E27; GF(3)),
      represented by
      [2 0 0 0 0 0 0]
      sage: print(R.6*R.8)
      4-Cocycle in H^*(E27; GF(3)),
      represented by
      [1 0 0 0 0 0 0]
      sage: c=R('a_1_0*a_1_1*b_2_0+b_2_1^2')
      sage: c.name()
      '((a_1_0)*(a_1_1))*(b_2_0)+(b_2_1)**2'
      sage: c.setname('C')
      sage: c
      C: 4-Cocycle in H^*(E27; GF(3))
      sage: R.poincare_series()
      (t^4 + 2*t^2 + 1)/(t^6 - 2*t^5 + 2*t^4 - 2*t^3 + 2*t^2 - 2*t + 1)
      sage: R._poincare_without_parameters()
      (t^4 + 2*t^2 + 1)/(t^6 - 2*t^5 + 2*t^4 - 2*t^3 + 2*t^2 - 2*t + 1)

  We return to our standard example, the cohomology of the dihedral group of order 8:

      sage: CohomologyRing.set_workspace(tmp_root)
      sage: H = CohomologyRing(8,3)
      sage: H.make()

  First of all, the attribute ‘completed’ tells whether the cohomology computation has been successfully finished. The attribute ‘knownDeg’ tells up to what degree the ring structure is explored, ‘lastRel’ is the degree of the last found relation, and ‘_method’ states whose criterion was used to prove completeness:

      sage: H.completed
      True
      sage: H.knownDeg
      2
      sage: H.lastRel
      2
      sage: H._method
      'Symonds'

  A cohomology ring is based on some minimal projective resolution (see `RESL`):

      sage: H.resolution()
      Resolution of GF(2)[D8]

  The lists of generators and relations of a cohomology ring can be obtained with `gens()` and `rels()`.

  The attribute `H.GenS` provides a ring defined in the Singular interface, and `H.RelG` is a list of strings defining a Groebner basis for the relation ideal. The cohomology ring is isomorphic to the quotient of `H.GenS` by the ideal of `H.RelG`. The same ring is created when putting `H` into the singular interface:

      sage: H.GenS.set_ring()
      sage: I=H.GenS.parent().ideal(H.RelG)
      sage: s=H.GenS.parent().eval('qring Q = %s'%(I.name()))
      sage: H.GenS.parent()('Q')
      polynomial ring, over a field, global ordering
      // coefficients: ZZ/2
      // number of vars : 3
      //        block   1 : ordering M
      //                  : names    c_2_2 b_1_0 b_1_1
      //                  : weights      2     1     1
      //                  : weights     -1     0     0
      //                  : weights      0    -1     0
      //        block   2 : ordering C
      // quotient ring from ideal
      _[1]=b_1_0*b_1_1
      sage: singular(H)
      polynomial ring, over a field, global ordering
      // coefficients: ZZ/2
      // number of vars : 3
      //        block   1 : ordering M
      //                  : names    c_2_2 b_1_0 b_1_1
      //                  : weights      2     1     1
      //                  : weights     -1     0     0
      //                  : weights      0    -1     0
      //        block   2 : ordering C
      // quotient ring from ideal ...

  The computation of a cohomology ring makes heavy use of the Singular interface. The names of all data in Singular that are related with a specific cohomology ring `H` have a common prefix, namely `H.prefix`. The prefix is chosen automatically and is different for any instance of `COHO`:

      sage: H.prefix==H.subgps[(4,2)].prefix
      False

  In the Singular interface, a graded commutative polynomial ring is defined and can be addressed as follows:

      sage: print(singular.eval('%sr(%d)'%(H.prefix,H.knownDeg)))
      // coefficients: ZZ/2
      // number of vars : 3
      //        block   1 : ordering M
      //                  : names    c_2_2 b_1_0 b_1_1
      //                  : weights      2     1     1
      //                  : weights     -1     0     0
      //                  : weights      0    -1     0
      //        block   2 : ordering C

  Note that in Singular, ideals are only available if the ring to which the ideal belongs is Singular’s current `basering`. Currently, the quotient ring defined above is `basering`. We change the base ring, and then a Groebner basis at least up to degree `H.knownDeg` is given as follows:

      sage: H.set_ring()
      sage: singular('%sI'%(H.prefix))
      b_1_0*b_1_1

  We change the base ring again,

      sage: H.subgroups()[(4,2)].set_ring()

  and then of course the relation ideal of `H` is not available anymore:

      sage: singular('%sI'%(H.prefix))
      Traceback (most recent call last):
      ...
      TypeError: Singular error:
        ? ... is undefined
        ? error occurred in ...: `def ...;`

  Custom attributes

  In Python, it is possible to add attributes to any object. However, when adding a Python attribute to a cohomology ring, it would be lost when saving.

  Therefore we provide another way to add custom “attributes” to a cohomology ring. We refer to such attribute as a “property” of the ring.

  Properties can be retreived in the same way as usual attributes, they are visible in tab completion and in introspection, and they are preserved when the cohomology ring is saved and reloaded. This is very useful for adding more information.

  When an attribute of the requested name (`Status` in the following example) does not exist, it is checked whether a property of that name has yet been defined. If this is the case, it is returned, otherwise None is returned. Note that for cohomology rings you will never get an ``AttributeError`` except for attributes that start and end with an underscore:

      sage: H._foobar_
      Traceback (most recent call last):
      ...
      AttributeError: 'COHO' object has no attribute '_foobar_'
      sage: print(H.Status)  # not defined at that point, hence "None"
      None
      sage: 'Status' in dir(H)
      False
      sage: H.setprop('Status','Our main example')
      sage: H.Status
      'Our main example'
      sage: 'Status' in dir(H)
      True

  Usually, cohomology rings that are created using the constructor `CohomologyRing()` are cached:

      sage: H is loads(dumps(H))
      True

  We destroy the cache on purpose and demonstrate that the additional property is preserved by pickling:

      sage: del CohomologyRing._cache[H._key]
      sage: HR = loads(dumps(H))
      sage: HR is H
      False
      sage: HR.Status
      'Our main example'

  Among many other data, the group name (that we passed on by the parameter `GroupName`) and a more detailed autogenerated group description (that can be overwritten using `setprop('GroupDescr',...)` ) are provided in form of custom attributes:

      sage: H.GroupName  # This comes from a list of known group names
      'D8'
      sage: H.GroupDescr # This comes from a list of known group descriptions
      'Dihedral group of order 8'

  The custom attribute ‘Status’ can be deleted with

      sage: H.delprop('Status')
      sage: print(H.Status)
      None
      sage: 'Status' in dir(H)
      False

  TESTS:

  As mentioned above, there are various global options (both in the definition of a cohomology ring and by using CohomologyRing.global_options(…)) that influence the choice of algorithm. For unit testing, we repeat here one of the examples from above. In order to not loose too much time, we now allow to reload data.

      sage: CohomologyRing.global_options('reload')

  First, we use linear algebra and not elimination for finding the Dickson classes:

      sage: H4 = COHO(64,14,root=tmp_root, useElimination=False)
      sage: H4.make()
      sage: H4.gens()
      [1,
       a_2_1: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_2_2: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_4_4: 4-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_0: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_1: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_3_3: 3-Cocycle in H^*(SmallGroup(64,14); GF(2))]

  It depends on the python version whether or not the relations are tail-reduced and how they are sorted:

      sage: if (2, 8) < sys.version_info:
      ....:     expected_rels = ['a_1_0^2', 'a_1_0*a_1_1', 'a_1_1^3', 'a_2_1*a_1_0',
      ....:           'a_2_1^2+a_2_1*a_1_1^2', 'a_1_0*a_3_3+a_2_1*a_1_1^2',
      ....:           'a_1_1*a_3_3+a_2_1*a_1_1^2', 'a_2_1*a_3_3', 'a_3_3^2']
      ....: else:
      ....:     expected_rels = ['a_1_0^2', 'a_1_0*a_1_1', 'a_1_1^3', 'a_2_1*a_1_0',
      ....:           'a_2_1^2+a_2_1*a_1_1^2', 'a_1_1*a_3_3+a_2_1^2',
      ....:           'a_1_0*a_3_3+a_2_1^2', 'a_2_1*a_3_3', 'a_3_3^2']
      ....:
      sage: H4.rels() == expected_rels
      True

  We repeat the example, but this time use elimination.

      sage: H4 = COHO(64,14,root=tmp_root, useElimination=True)
      sage: H4.make()
      sage: H4.gens()
      [1,
       a_2_1: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_2_2: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_4_4: 4-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_0: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_1: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_3_3: 3-Cocycle in H^*(SmallGroup(64,14); GF(2))]
      sage: H4.rels() == expected_rels
      True

  Now we switch the ‘sparse’ option on:

      sage: CohomologyRing.global_options('sparse')
      sage: H4 = COHO(64,14,root=tmp_root)
      sage: H4.make()
      sage: H4.gens()
      [1,
       a_2_1: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_2_2: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_4_4: 4-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_0: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_1: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_3_3: 3-Cocycle in H^*(SmallGroup(64,14); GF(2))]
      sage: H4.rels() == expected_rels
      True
      sage: CohomologyRing.global_options('nosparse')

  And finally, we allow to convert to Sage matrices in some steps of the computation:

      sage: H4 = COHO(64,14,root=tmp_root)
      sage: CohomologyRing.global_options('nouseMTX')
      sage: H4.make()
      sage: H4.gens()
      [1,
       a_2_1: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_2_2: 2-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       c_4_4: 4-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_0: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_1_1: 1-Cocycle in H^*(SmallGroup(64,14); GF(2)),
       a_3_3: 3-Cocycle in H^*(SmallGroup(64,14); GF(2))]
      sage: H4.rels() == expected_rels
      True
      sage: CohomologyRing.global_options('useMTX')

  `BensonTest`(FRS, dv, forced=False)

    A modified version of Benson’s completeness criterion.

    INPUT:

    - `FRS`, a list of strings providing elements of `self` that are known to provide a filter regular HSOP for the cohomology ring

    - `dv`, the degrees (list of integers) of these parameters

    - `forced` [optional, default = `False`]: If `True`, perform Benson’s test even if it seems to be too low degree

    OUTPUT:

    - `True` if the test succeeded

    - `None` if the test was not conclusive

    - `False` if the test showed that the ring is incomplete.

    The attribute `suffDeg` may be modified.

    THEORY:

    See [GreenKing] and the outline we gave in `pGroupCohomology`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(64,6, useElimination=True, from_scratch=True)
        sage: H.next()

    There are no suitable parameters of the current ring approximation, so that a completion test wouldn’t make sense yet. So, we continue, and succeed with finding filter regular parameters:

        sage: H.filter_regular_parameters()
        sage: H.next()
        sage: H.filter_regular_parameters()
        ['c_2_2', 'c_2_3', 'b_1_1']

    It is not reasonable to apply Benson’s test, yet, since we expect a relation in degree 4:

        sage: H.expect_last_relation()
        4

    And of course, the degrees of the parameters do not allow to prove completeness already in degree two:

        sage: CohomologyRing.global_options('info')
        sage: H.BensonTest(H.filter_regular_parameters(),[2,2,1])
        H^*(SmallGroup(64,6); GF(2)):
            Testing whether it makes sense to try Benson's completeness criterion
            We expect that Benson's test will not apply before degree 3

    So, we must go ahead. The log states that Benson’s test will not apply before degree three. Perhaps it does apply in that degree, although we expect a relation in degree four?

        sage: CohomologyRing.global_options('warn')
        sage: H.next()
        sage: CohomologyRing.global_options('info')
        sage: H.BensonTest(H.filter_regular_parameters(),[2,2,1])
        H^*(SmallGroup(64,6); GF(2)):
            Testing whether it makes sense to try Benson's completeness criterion
            It is possible that Benson's degree bound applies
            Compute raw_filter_degree_type
            Computing complete Groebner basis
            Test filter regularity
            > Sequence is NOT filter regular. Sorry.
        False

    It does not. But in degree 4, everything works:

        sage: CohomologyRing.global_options('warn')
        sage: H.next()
        sage: CohomologyRing.global_options('info')
        sage: H.BensonTest(H.filter_regular_parameters(),[2,2,1])
        H^*(SmallGroup(64,6); GF(2)):
            Testing whether it makes sense to try Benson's completeness criterion
            It is possible that Benson's degree bound applies
            Compute raw_filter_degree_type
            Computing complete Groebner basis
            Test filter regularity
              Filter degree type: [-1, -2, -3, -3]
        True

    Now the ‘sufficient degree’ is less than or equal to the known degree, hence, we are done:

        sage: H.suffDeg
        3
        sage: H.knownDeg
        4
        sage: CohomologyRing.global_options('warn')

  `Hom`(other, category=None)

    Return a homset of induced homomorphisms between two cohomology rings.

    INPUT:

    - A cohomology ring that will be the codomain for all elements of the homset

    - `cat` (not implemented) a category of homomorphisms.

    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: H1 = CohomologyRing(8,3)
        sage: H2 = CohomologyRing(libgap.DihedralGroup(8), GroupName = 'DihedralGroup(8)', from_scratch=True)
        sage: H1.Hom(H2)
        Set of Homomorphisms from H^*(D8; GF(2)) to H^*(DihedralGroup(8); GF(2))

  `InitSubgroups`()

    Initialise maximal elementary abelian subgroups.

    If self is the cohomology ring of a non-abelian \(p\)-group then `InitSubgroups` initialises various group theoretic data, such as the \(p\)-rank or the rank of the center; it also creates or reloads the cohomology rings of the greatest central and the maximal elementary abelian subgroups, and, if applicable, computes the Dickson classes of the maximal elementary abelian subgroups.

    NOTE:

    This function should only be of internal use and will be invoked when initializing a cohomology ring. It requires the presence of a certain GAP-readable file that is created during initialisation of the cohomology ring.

    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)

    Now we destroy and reconstruct the subgroups and the respective restriction maps:

        sage: H.subgps={}
        sage: H.RestrMaps={}
        sage: H.InitSubgroups()
        sage: sorted(H.subgroups().items())
        [((2, 1), H^*(SmallGroup(2,1); GF(2))), ((4, 2), H^*(SmallGroup(4,2); GF(2)))]
        sage: sorted(H.restriction_maps().items())
        [(1,
          [(2, 1),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(2,1); GF(2))]),
         (2,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))]),
         (3,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))])]
        sage: H.subgpDickson
        {(4, 2): [c_1_1: 1-Cocycle in H^*(SmallGroup(4,2); GF(2))]}

    Finally, we show location and content of the GAP-readable file that defines the subgroup structure:

        sage: print(open(os.path.join(H.inc_folder,H.GStem+'.sgs')).read())
        # Subgroup information for 8gp3
        local numSpecialSubgps, specialSubgpId, CrankPos, numMaxels,
          maxelRankPos, numBoltons, Bolton;
        numSpecialSubgps := 3;
        specialSubgpId := [ [ 2, 1 ], [ 4, 2 ], [ 4, 2 ] ];
        CrankPos := [ 1, 1 ];
        numMaxels := 2;
        maxelRankPos := [ [ 2, 2 ], [ 2, 3 ] ];
        numBoltons := 0;
        Bolton := [];
        return [numSpecialSubgps, specialSubgpId, CrankPos,
          numMaxels, maxelRankPos, numBoltons, Bolton];

  `InsertSubgroup`(q, nr, n)

    Initialize the restriction map to some subgroup.

    INPUT:

    - `q` - the order of the subgroup

    - `nr` - the position of this group in the Small Group Library

    - `n` - the subgroup is addressed as subgroup number `n`

    NOTE:

    - This method will normally be of internal use only. It is invoked by the method `InitSubgroups()`

    - It reads the data for the inclusion map from a file whose name is determined by `self.GStem` and `n`. The necessary files are created by `makeGroupData()` or or `makeSpecialGroupData()` during iniitialisation of the cohomology ring.

    - Normally, we only consider elementary abelian subgroups. This method probably also allows for insertion of other interesting subgroups, provided a file with data for the inclusion map exists. However, PLEASE DO NOT INSERT SUBGROUPS MANUALLY! The computations crucially depend on the restrictions to certain elementary abelian subgroups, and it is essential that only elementary abelian abelian subgroups are inserted, including the greatest central elementary abelian (this must be subgroup number one) and one representative for each conjugacy class of maximal elementary abelian subgroups.

    - The method will try to read a file in a specific location (see example below). This file should provide a MeatAxe matrix that describes the inclusion map of the algebra of the subgroup into the algebra of the ambient group.

    - When a cohomology ring is initialized, the greatest central elementary abelian subgroup will be inserted as special subgroup number 1. Moreover, representatives for the conjugacy classes of maximal elementary subgroups will be inserted.

    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: sorted(H.subgroups().items())
        [((2, 1), H^*(SmallGroup(2,1); GF(2))), ((4, 2), H^*(SmallGroup(4,2); GF(2)))]
        sage: sorted(H.restriction_maps().items())
        [(1,
          [(2, 1),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(2,1); GF(2))]),
         (2,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))]),
         (3,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))])]

    Hence, there are 3 special subgroups, that are of two different isomorphism types. We now destroy them on purpose:

        sage: H.RestrMaps={}
        sage: H.subgps={}

    Next, we put them back manually. Note that it is attempted to reload the subgroups from cache or from disk:

        sage: H.InsertSubgroup(2,1,1)
        sage: H.InsertSubgroup(4,2,2)

    The third subgroup has the same automorphism type as the second, so, there is no need to reload it, but it doesn’t hurt either:

        sage: H.InsertSubgroup(4,2,3)
        sage: sorted(H.subgroups().items())
        [((2, 1), H^*(SmallGroup(2,1); GF(2))), ((4, 2), H^*(SmallGroup(4,2); GF(2)))]
        sage: sorted(H.restriction_maps().items())
        [(1,
          [(2, 1),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(2,1); GF(2))]),
         (2,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))]),
         (3,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2))])]

    Next, we show where to find the files defining the inclusion of the second and third subgroup. Although they are isomorphic, the inclusions are, of course, different:

        sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX
        sage: print(MTX.from_filename(os.path.join(H.inc_folder,H.GStem+'sg2.ima')))
        [1 0 0 0 0 0 0 0]
        [0 0 0 1 1 1 1 1]
        [0 0 1 0 0 0 0 0]
        [0 0 0 0 0 0 1 1]
        sage: print(MTX.from_filename(os.path.join(H.inc_folder,H.GStem+'sg3.ima')))
        [1 0 0 0 0 0 0 0]
        [0 0 0 1 1 1 1 1]
        [0 1 0 0 0 0 0 0]
        [0 0 0 0 0 1 0 1]

    Finally, we demonstrate how to continue the computation. After re-inserting the special subgroups, it is necessary to re-compute the Dickson classes in the special subgroups (using the method dickson_in_subgroup), or to use the elimination method. We chose the second way:

        sage: H.setprop('useElimination',True)
        sage: CohomologyRing.global_options('warn')
        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]

  `MonToProd`(expV)

    Return the element corresponding to a list of exponents.

    INPUT:

    `expV`: a list of non-negative integers (exponents of a list of monomials)

    OUTPUT:

    An element of `self` (`COCH`), given by a power product of generators.

    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: H.MonToProd([0,2,1])
        (b_1_0)*((b_1_0)*(b_1_1)): 3-Cocycle in H^*(D8; GF(2))

  `PrescribedRestrictions`(L)

    Try to construct a cochain of `self` that has given restrictions to the elementary abelian subgroups.

    INPUT:

    - `L`: a list of elements of the form `[i,C]`, where

      - `i`: the identifier (integer) of a special subgroup

      - `C`: an element of the `i`-th special subgroup

    OUTPUT:

    A cochain that has restrictions prescribed in `L`, or `None`, if such cochain doesn’t exist.

    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()

    To simplify notation, we give names to the two isomorphism types of special subgroups:

        sage: Z = H.subgps[(2,1)]
        sage: M = H.subgps[(4,2)]

    We define cochains in `Z` and in `M`, and try to find common lifts in `H`. Note that `M` corresponds to two pairwise non-conjugate maximal elementary abelian subgroups of the dihedral group, while `Z` corresponds to the greatest central elementary abelian subgroup.

        sage: c = Z.standardCochain(2,0)
        sage: m1 = M.standardCochain(2,0)
        sage: m2 = M.standardCochain(2,1)
        sage: m3 = M.standardCochain(2,2)
        sage: print(H.PrescribedRestrictions([[1,c],[2,m2]]))
        None
        sage: print(H.PrescribedRestrictions([[1,c],[2,m1+m2]]))
        2-Cocycle in H^*(D8; GF(2)),
        represented by
        [0 0 1]

    Note that the lift is not unique. If we also prescribe a cochain in the third pecial subgroup, we still get a lift of `[1,c]` and `[2,m1+m2]`, but a different lift:

        sage: print(H.PrescribedRestrictions([[1,c],[2,m1+m2],[3,m1+m2+m3]]))
        2-Cocycle in H^*(D8; GF(2)),
        represented by
        [0 1 1]

    Finally, we test whether we really have the restrictions that we want:

        sage: L = H.PrescribedRestrictions([[1,c],[2,m1+m2],[3,m1+m2+m3]])
        sage: H.restriction_maps()[1][1](L) == c
        True
        sage: H.restriction_maps()[2][1](L) == m1+m2
        True
        sage: H.restriction_maps()[3][1](L) == m1+m2+m3
        True

  `SymondsTest`(hsop, dv, forced=False)

    Apply the Symonds test.

    INPUT:

    - `hsop`: A list of strings defining a homogeneous system of parameters for the current ring approximation.

    - `dv`: The degrees (list of integers) of `hsop`.

    OUTPUT:

    - `True`, `False` or `None`, depending on whether the criterion proves completeness, the approximation is provably incomplete, or there is no conclusive application of the criterion possible yet.

    - The attribute `_max_module_deg` is set.

    ASSUMPTION:

    The ring approximation contains paramters for the cohomology ring.

    THEORY:

    By [Symonds], under the above assumption, the ring approximation is complete if it is known to a degree greater than the sum of the degrees in `hsop` minus their number, and the ring approximation is generated at most out to that degree as a module over the algebra generated by `hsop`.

    NOTE:

    The method `test_for_completion()` chooses between the modified Benson test and the Symonds test.

    EXAMPLES:

    We compute a cohomology ring out to degree 10, avoiding automatic application of the criterion.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(64,32, from_scratch=True)
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.knownDeg
        10

    There are fairly small parameters:

        sage: H.parameters()
        ['c_4_11', 'b_2_3+b_2_2+b_2_1', 'b_2_2+b_2_1', 'b_1_1']
        sage: H.verify_parameters_exist()
        True

    The previous line asserts that the assumption of this criterion is satisfied. Indeed, the criterion applies:

        sage: H.SymondsTest(H.parameters(),[4,2,2,1])
        True

    As a module, the ring is generated in degree at most five:

        sage: H._max_module_deg
        5

  `a_invariants`()

    Permanently cached method: Return the \(a\)-invariants of `self`.

    THEORY:

    A filter regular homogeneous system of paramaters can be used for an iterative computation of the \(a\)-invariants, provided the parameters are of sufficiently high degree. Often the data obtained by verifying Benson’s completeness criterion are sufficient for the computation of \(a\)-invariants. However, in some cases it is needed to raise the parameters occuring in Benson’s criterion to some power.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3, useElimination=True, from_scratch=True)
        sage: H.make()
        sage: H.a_invariants()
        [-Infinity, -Infinity, -2]

    The attribute `H.A_INV_Expos` tells whether it was needed to raise the parameters to some power (this is not the case here):

        sage: H.A_INV_Expos
        [1, 1]

  `autosave_name`()

    Return the name of the file under which `self` is automatically saved.

    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: H is load(H.autosave_name())
        True

  `bar_code`(command, degree=- 1)

    Permanently cached method: Compute the persistent cohomology for a specified normal subgroup series.

    ASSUMPTION:

    The subgroups and quotient groups can be found in the SmallGroups library.

    INPUT:

    `command`: The name (string) of a Gap command that produces

      a series of normal subgroups when applied to the group `self.group()`, starting with `self.group()` and terminating with the trivial group.

    `degree=-1`: Optional parameter. If `degree>=0` then only

      the bar code in the specified degree is computed; otherwise, all degrees are studied simultaneously, by Poincaré series.

    OUTPUT:

    `self`’s full bar code (class `BarCode`) respectively bar code of the given degree (class `BarCode2d`), associated with the specified normal series.

    THEORY:

    Any sequence of group homomorphisms \(\phi_i: G_i \to G_{i+1}\) with \(i=1,...,n\) gives rise to a series of induced homomorphisms of cohomology rings. Persistent group cohomology, introduced by [EllisKing], asks how long cocycles in a given degree”survive” being mapped by the induced homomorphisms. For a given degree \(d\), the persistent cohomology can be described by an upper triangular matrix of non-negative integers, where entry \(i,j\) (\(i\le j\)) is the dimension of the image of the degree \(d\) part of \(H^*(G_j)\) in \(H^*(G_i)\) under the induced homomorphism given by the composition of \(\phi_i,\phi_{i+1},...,\phi_{j-1}\), including the case \(i=j\) in which the matrix entry simply gives the dimension of the degree \(d\) part of \(H^*(G_i)\).

    As usual, the sequence of dimensions sorted by degree gives rise to a Poincaré series. Hence, an upper triangular matrix of rational functions results and this provides information for all degrees.

    EXAMPLES:

    We work here with groups of order 64, that are part of the cohomology data base shipped with this package.

        sage: from pGroupCohomology import CohomologyRing
        sage: H158 = CohomologyRing(64,158)
        sage: H158.make()
        sage: H160 = CohomologyRing(64,160)
        sage: H160.make()

    The Poincaré series, the \(a\)-invariants, the degrees of generators and of relations of the cohomology rings coincide:

        sage: H158.poincare_series()
        (t^4 + t^3 + t^2 + t + 1)/(t^6 - 2*t^5 + 3*t^4 - 4*t^3 + 3*t^2 - 2*t + 1)
        sage: H160.poincare_series()
        (t^4 + t^3 + t^2 + t + 1)/(t^6 - 2*t^5 + 3*t^4 - 4*t^3 + 3*t^2 - 2*t + 1)
        sage: H158.degvec
        [4, 4, 1, 1, 1, 3, 3]
        sage: H160.degvec
        [4, 4, 1, 1, 1, 3, 3]
        sage: H158.set_ring()
        sage: [singular('deg(%s)'%r) for r in H158.rels()]
        [2, 2, 3, 3, 4, 4, 5, 6, 6, 6]
        sage: H160.set_ring()
        sage: [singular('deg(%s)'%r) for r in H160.rels()]
        [2, 2, 3, 3, 4, 4, 5, 6, 6, 6]
        sage: H158.a_invariants()
        [-Infinity, -Infinity, -2]
        sage: H160.a_invariants()
        [-Infinity, -Infinity, -2]

    We consider here the bar codes associated with the upper central series. It turns out that the non-trivial terms of the upper central series and the resulting factor groups are isomorphic:

        sage: G158 = libgap.SmallGroup(64,158)
        sage: G160 = libgap.SmallGroup(64,160)
        sage: [(G.IdGroup(), (G158/G).IdGroup()) for G in G158.UpperCentralSeries()]
        [([ 64, 158 ], [ 1, 1 ]),
         ([ 16, 2 ], [ 4, 2 ]),
         ([ 4, 2 ], [ 16, 11 ]),
         ([ 1, 1 ], [ 64, 158 ])]
        sage: [(G.IdGroup(), (G160/G).IdGroup()) for G in G160.UpperCentralSeries()]
        [([ 64, 160 ], [ 1, 1 ]),
         ([ 16, 2 ], [ 4, 2 ]),
         ([ 4, 2 ], [ 16, 11 ]),
         ([ 1, 1 ], [ 64, 160 ])]

    Nevertheless, the groups can be distinguished using the bar codes associated with the upper central series:

        sage: B158 = H158.bar_code('UpperCentralSeries')
        sage: B160 = H160.bar_code('UpperCentralSeries')
        sage: B158 == B160
        False

    Indeed, the bar codes differ in degree 3; graphically:

        sage: ascii_art(B158[3])
                *
                *
              *-*
              *-*
              *
              *
              *
              *
              *
              *
            *-*
            *-*
            *
            *
          *
          *
          *
          *
        *
        *
        *
        *
        sage: ascii_art(B160[3])
                *
                *
              *-*
              *
              *
              *
              *
              *
              *
              *
            *-*-*
            *-*
            *
          *-*
          *
          *
          *
        *
        *
        *
        *

    These pictures (bar codes) can be interpreted as follows. Let \(G\) be a finite \(p\)-group and let \(G=G_0 > G_1 > ... > G_n > 1\) be a normal series; in our example, we have \(n=2\). The first \(n+1\) columns of the bar code correspond to the normal subgroups groups \(G_n, G_{n-1},..., G_0\), while the last \(n\) columns correspond to the factor groups \(G/G_n, G/G_{n-1},..., G/G_1\). We consider the sequence of group homomorphisms given by inclusions and quotients. The stars in the bar code correspond to basis vectors of the degree \(d\) part of the cohomology rings of the respective groups. Stars are connected by a line (i.e., a hyphen) if the corresponding basis vectors are mapped to each other by the induced maps (which of course go from right to left).

    In terms of the persistance matrix:

        sage: B158[3].matrix()
        [ 4  0  0  0  0]
        [ 0  4  0  0  0]
        [ 0  0  4  2  0]
        [ 0  0  0 10  2]
        [ 0  0  0  0  4]
        sage: B160[3].matrix()
        [ 4  0  0  0  0]
        [ 0  4  1  0  0]
        [ 0  0  4  2  1]
        [ 0  0  0 10  2]
        [ 0  0  0  0  4]

    The bar codes in degree 3 can also be computed directly, and of course it coincides with the bar codes obtained from the “full” bar codes (based on Poincaré series):

        sage: B158[3] == H158.bar_code('UpperCentralSeries',degree=3)
        True
        sage: B160[3] == H160.bar_code('UpperCentralSeries',degree=3)
        True

    Since apparently the `(2,4)` entries of the persistence matrices differ, we show here how the Poincaré series in that position look like:

        sage: B158.matrix()[2,4]
        2*t^2 + 2*t + 1
        sage: B160.matrix()[2,4]
        t^3 + 2*t^2 + 2*t + 1

    Hence, the image of the map \(H^*(G/G_2) \to H^*(G)\) induced by the quotient map contains only finitely many cocycles, where \(G\) is group number 158 or 160 of order 64, and \(G_2\) is the second term of the upper central series.

  `decomposable_classes`(n, forced=False)

    Return a basis for the degree \(n\) cohomology, expressed by monomials.

    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.decomposable_classes(3)
        [(b_1_0)*((b_1_0)*(b_1_0)): 3-Cocycle in H^*(D8; GF(2)),
         (b_1_1)*((b_1_1)*(b_1_1)): 3-Cocycle in H^*(D8; GF(2)),
         (b_1_0)*(c_2_2): 3-Cocycle in H^*(D8; GF(2)),
         (b_1_1)*(c_2_2): 3-Cocycle in H^*(D8; GF(2))]

  `delprop`(key)

    Delete a property of `self`.

    TESTS:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.setprop('_foobar_', 'It works!')
        sage: print(H._foobar_)
        It works!
        sage: H.delprop('_foobar_')
        sage: H._foobar_
        Traceback (most recent call last):
        ...
        AttributeError: 'COHO' object has no attribute '_foobar_'

  `dependent_parameters`()

    Permanently cached method: Parameters for the cohomology that are not guaranteed to be algebraically independent.

    OUTPUT:

    A subset of ring generators of the current ring approximation over which the cohomology ring is finite.

    NOTE:

    There is no guarantee that they give rise to parameters for the current ring approximation. There is no guarantee that the returned elements are algebraically independent.

    Since elements of degree one do not contribute to the degree bound in Symonds’ completeness criterion, we always include the degree one generators.

    This method is applied for the Symonds test (see `SymondsTest()`).

    EXAMPLE:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(32,32, from_scratch=True)
        sage: H.make(2)

    The current ring approximation does not contain parameters for the cohomology ring, and thus we obtain:

        sage: H.verify_parameters_exist()
        False
        sage: print(H.dependent_parameters())
        None

    In degree 4, at last we find that the cohomology ring is finite over the returned element list, so that it can eventually be used in a completeness test – even though the ring approximation isn’t finite over it, yet:

        sage: H.make(4)
        sage: H.verify_parameters_exist()
        True
        sage: H.dependent_parameters()
        ['a_1_0', 'a_1_1', 'a_1_2', 'c_4_4', 'c_4_5']
        sage: print(H)
        Cohomology ring of Small Group number 32 of order 32 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 4
        Minimal list of generators:
        [c_4_4: 4-Cocycle in H^*(SmallGroup(32,32); GF(2)),
         c_4_5: 4-Cocycle in H^*(SmallGroup(32,32); GF(2)),
         a_1_0: 1-Cocycle in H^*(SmallGroup(32,32); GF(2)),
         a_1_1: 1-Cocycle in H^*(SmallGroup(32,32); GF(2)),
         a_1_2: 1-Cocycle in H^*(SmallGroup(32,32); GF(2)),
         a_3_2: 3-Cocycle in H^*(SmallGroup(32,32); GF(2)),
         a_3_3: 3-Cocycle in H^*(SmallGroup(32,32); GF(2))]
        Minimal list of algebraic relations:
        [a_1_1^2+a_1_0*a_1_2,
         a_1_2^2+a_1_0*a_1_1+a_1_0^2,
         a_1_0^3,
         a_1_0^2*a_1_2+a_1_0^2*a_1_1,
         a_1_2*a_3_2+a_1_1*a_3_2+a_1_0*a_3_3+a_1_0*a_3_2,
         a_1_2*a_3_3+a_1_1*a_3_3+a_1_0*a_3_2]

  `depth`()

    Permanently cached method: Return the depth of `self`, i.e., the length of a maximal regular sequence.

    NOTE:

    By theorems of Duflot and Kuhn, the rank of the center of the underlying group is a lower bound for the depth. The \(p\)-rank of the group is equal to the dimension of the cohomology ring, and thus is an upper bound.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(32,27)
        sage: H.make()
        sage: H.dimension()
        4
        sage: H.CenterRk
        2
        sage: H.depth()
        3

  `depth_essential_ideal`(r)

    Permanently cached method: Compute the \(r\)-th depth essential ideal.

    INPUT:

    `r` – an integer, `self.CenterRk \le r \le self.dimension()`.

    OUTPUT:

    The ideal formed by all elements of `self` that restrict to zero on the centralisers of all \(p\)-elementary abelian subgroups of rank `r` (it suffices to consider those that are contained in a Sylow \(p\)-subgroup \(S\) and contain the greatest central elementary abelian subgroup of \(S\).

    THEORY:

    If `r` is at most the depth of `self`, then the result is zero. It is conjectured by J. Carlson that it is non-zero whenever `r` exceeds the depth.

    EXAMPLE:

    We choose a group of order 64 (that is contained in the local sources shipped with this package), and verify Carlson’s conjecture:

        sage: from pGroupCohomology import CohomologyRing
        sage: H = CohomologyRing(64,23)
        sage: H.CenterRk
        2
        sage: H.depth()
        3
        sage: H.dimension()
        4
        sage: H.depth_essential_ideal(2)
        0
        sage: H.depth_essential_ideal(3)
        0
        sage: H.depth_essential_ideal(4)
        a_1_0,
        a_1_1,
        a_2_0

  `dickson_in_subgroup`(ID)

    Compute Dickson classes for an elementary abelian group, considered as subgroup of the group of \(self\).

    INPUT:

    - `ID`: the small groups address (pair of integers) of some elementary abelian subgroup of `self`.

    OUTPUT:

    Let \(G\) be the finite \(p\)-group whose cohomology ring `self` represents. The attribute `subgbDickson` of self is changed and contains elements of degree \(p^{r-z}-p^{r-z-i}\) of the cohomology ring of the elementary abelian group \(V\) described by `ID`, where \(r\) is the \(p\)-rank of \(G\), \(z\) is the rank of the centre of \(G\), and \(i = 1,...,r-z\). These elements are constructed using Dickson invariants in the polynomial part of the cohomology of \(V\), vanishing on the first \(z\) generators. Note that in some cases a trivial element results, but it still has the stated degree.

    NOTE:

    For applying Benson’s or Symonds’ completeness criterion, one has to find Dickson classes in the ambient group that simultaneously restrict to (powers of) the classes in the special subgroups found with dickson_in_subgroup. However, if \(p^{r-z}-p^{r-z-i}\) is too large, one should use `find_dickson()`, that avoids the construction of elements of high degrees.

    EXAMPLES:

    We choose a group that has two different isomorphism classes of maximal elementary abelian subgroups:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(32,27, from_scratch=True)

    The Dickson invariants for the maximal elementary abelian subgroups were already computed when creating `H`. We destroy them on purpose and reconstruct them:

        sage: H.subgpDickson = {}
        sage: H.dickson_in_subgroup((8,5))
        sage: sorted(H.subgpDickson.items())
        [((8, 5),
          [(c_1_2)**2: 2-Cocycle in H^*(SmallGroup(8,5); GF(2)),
           0: 3-Cocycle in H^*(SmallGroup(8,5); GF(2))])]
        sage: H.dickson_in_subgroup((16,14))
        sage: sorted(H.subgpDickson.items())
        [((8, 5),
          [(c_1_2)**2: 2-Cocycle in H^*(SmallGroup(8,5); GF(2)),
           0: 3-Cocycle in H^*(SmallGroup(8,5); GF(2))]),
         ((16, 14),
          [(c_1_2)*(c_1_2)+(c_1_2)*(c_1_3)+(c_1_3)*(c_1_3): 2-Cocycle in H^*(SmallGroup(16,14); GF(2)),
           (c_1_2)*((c_1_2)*(c_1_3))+(c_1_2)*((c_1_3)*(c_1_3)): 3-Cocycle in H^*(SmallGroup(16,14); GF(2))])]

  `dimension`()

    Return the dimension of `self`.

    NOTE:

    It is known that the dimension of self equals the \(p\)-rank of the underlying group.

    EXAMPLES:

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

  `duflot_regular_sequence`()

    Return a Duflot regular sequence that is maximal in the current ring approximation.

    THEORY:

    A sequence of elements is called Duflot regular, if its restrictions to the greatest \(p\)-elementary abelian subgroup in the centre of a Sylow \(p\)-subgroup is regular.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(144,186,prime=3, from_scratch=True)
        sage: H.sylow_cohomology().duflot_regular_sequence()
        ['c_2_1', 'c_2_2']
        sage: H.make(4)
        sage: H.duflot_regular_sequence()
        ['c_4_0']
        sage: H.make()
        sage: H.duflot_regular_sequence()
        ['c_4_0', 'c_8_1']

    We compute the restrictions to the greatest central elementary abelian subgroup of a Sylow \(3\)-subgroup is a regular sequence, which are indeed regular:

        sage: r = H.restriction_maps()[1][1]; r
        Induced homomorphism of degree 0 from H^*(SmallGroup(144,186); GF(3)) to H^*(SmallGroup(9,2); GF(3))
        sage: [r(H(t)).as_polynomial() for t in H.duflot_regular_sequence()]
        ['c_2_2^2+c_2_1^2', 'c_2_1^2*c_2_2^2']

  `element_as_polynomial`(c)

    Express a cochain as polynomial in the generators of `self`.

    INPUT:

    `C`: an element of self

    OUTPUT:

    `C` is changed in-place and then returned, so that its name represents `C` as a polynomial in the ring generators.

    NOTE:

    If needed, all decomposable classes in the degree of `C` will be computed and then kept in memory. The decomposable classes need to be obtained anyway when computing the ring structure. By default, for saving resources, the memory is cleared (except for elementary abelian groups). If the optional parameter `KeepBases` is `True` when creating the cohomology ring, the memory is not cleared.

    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.standardCochain(3,3)
        sage: c
        c_3_3: 3-Cocycle in H^*(D8; GF(2))
        sage: c is H.element_as_polynomial(c)
        True
        sage: c
        c_2_2*b_1_1: 3-Cocycle in H^*(D8; GF(2))
        sage: H('c_2_2*b_1_1')==c
        True

  `essential_ideal`(Subgroups=None)

    Permanently cached method: Return the essential ideal, given by a Groebner basis.

    INPUT:

    `Subgroups` – optional list or set of subgroups of `self.group()`

    OUTPUT:

    The ideal of all elements of `singular(self)` that restrict to zero on all maximal subgroups of `self.group()` (resp. on the subgroups in the list `Subgroups`). The generators of this ideal form a Groebner basis.

    If the optional argument is not provided, then the essential ideal with respect to all maximal subgroups is returned, and theoretical results are used that in some cases assert that there are no essential classes.

    THEORY:

    The essential ideal is formed by those elements of the cohomology ring whose restriction to any proper subgroup vanishes. We compute it by intersecting the kernels of the restriction maps to all maximal subgroups.

    It is known that the essential ideal can only be non-zero if the group is of prime power order and if the depth does not exceed the Duflot bound.

    EXAMPLES:

    We compute the cohomology rings for the dihedral group of order 8, the quaternion group of order 8, the semi-dihedral group of order 16, and some group which is not of prime power order:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: D = CohomologyRing(8,3, from_scratch=True)
        sage: D.make()
        sage: Q = CohomologyRing(8,4, from_scratch=True)
        sage: Q.make()
        sage: SD = CohomologyRing(16,8, from_scratch=True)
        sage: SD.make()
        sage: S6 = CohomologyRing(720,763,prime=2, from_scratch=True)
        sage: S6.make()

    The quaternion group is the smallest group that has a non-vanishing essential ideal:

        sage: Q.essential_ideal()
        a_1_0^2,
        a_1_0*a_1_1

    The dihedral group and the group of order 720 (which is the symmetric group on 6 elements) have no essential classes, for different reasons:

        sage: CohomologyRing.global_options('info')
        sage: S6.essential_ideal()
        H^*(SmallGroup(720,763); GF(2)):
            Compute essential_ideal
            The group is not of prime power order -- there is no essential ideal
        0
        sage: D.essential_ideal()
        H^*(D8; GF(2)):
            Compute essential_ideal
            Compute depth
            Computation of depth interruptible with Ctrl-c
            Compute filter_regular_parameters
            Compute raw_filter_degree_type
              Test filter regularity
            Filter degree type: [-1, -2, -2]
            The depth exceeds the Duflot bound -- there is no essential ideal
        0

    Of course, if one provides the set of maximal subgroups as optional parameter, then the result is the same, but it makes no use of the theoretical result:

        sage: D.essential_ideal(D.group().MaximalSubgroups())
            Compute essential_ideal
            > computing kernel of an induced map
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            lift in the source resolution
            lift in the target resolution to degree 1
            lift in the source resolution
            lift in the target resolution to degree 2
        H^*(SmallGroup(4,2); GF(2)):
            Compute order_matrix
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            Compute preimages by elimination
        H^*(D8; GF(2)):
            > intersecting two ideals
            > computing kernel of an induced map
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            lift in the source resolution
            lift in the target resolution to degree 1
            lift in the source resolution
            lift in the target resolution to degree 2
            Compute preimages by elimination
        H^*(D8; GF(2)):
            > intersecting two ideals
            > preparing output
        0
        sage: CohomologyRing.global_options('warn')
        sage: S6.essential_ideal(S6.group().MaximalSubgroups())
        0

    The depths of `SD` coincides with the Duflot bound. However, it has no essential classes:

        sage: SD.essential_ideal()
        0

    There are, of course, elements that are essential with respect to only a subset of all subgroups:

        sage: SD.essential_ideal([SD.group().Centre(),SD.group().CommutatorSubgroup(SD.group())])
        a_1_0,
        b_1_1,
        b_3_1

    We now consider a more difficult example: The Sylow 2-subgroup of \(U_3(4)\), which is of order 64 and is thus contained in the local sources.

        sage: H = CohomologyRing(64,245)
        sage: H
        H^*(Syl2(U3(4)); GF(2))
        sage: I = H.essential_ideal()    #long time

    It turns out that there is exactly one essential class that decomposes into a product of other essential classes. Note that this cohomology ring is one of only two known examples in which the square of the essential ideal does not vanish. In previous Sage versions, there has been a bug in Singular’s `interred` command, so that a second element is printed that apparently is a multiple of the first. But now it is fine:

        sage: (I*I).NF('std(0)').interred()  #long time
        a_4_8*a_6_8*a_1_0^3*a_1_3
        sage: singular(H).set_ring()
        sage: singular('NF((a_4_8*a_6_8*a_1_0^3*a_1_3)^2, std(0))')
        0

    The second example was discovered using this package. It is the direct product of the cyclic group of order two and `SmallGroup(64,245)`. Again, there is precisely one essential class that can be written as a product of other essential classes.

  `expect_last_relation`()

    Returns a degree up to which there will provably be further non-obvious relations.

    ALGORITHM:

    1. If there are two different generators of degree \(d_1\) and \(d_2\) that are both not Duflot regular, then we expect a relation at least in degree \(d_1+d_2\).

    2. If there is a nilpotent generator in degree \(d\), then there will certainly be a relation in degree \(2d\). In the case of \(p\)-groups with \(p>2\), that relation is obvious for \(d\) odd and is not counted, and only part 1. applies.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(27,3, from_scratch=True)
        sage: H.make(3)
        sage: H.expect_last_relation()
        6

    Indeed, there are two different non-regular generators of degree 3:

        sage: H.7
        a_3_4: 3-Cocycle in H^*(E27; GF(3))
        sage: H.8
        a_3_5: 3-Cocycle in H^*(E27; GF(3))

  `exportMonomials`()

    Save previously computed standard monomials in a standard location.

    NOTE:

    This method is used when saving a cohomology ring. The saved standard monomials can be reloaded with `importMonomials()`, but this requires that the dictionary `self.Monomials` has the key `'bla'`.

    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: L1 = list(H.Monomials.items())
        sage: L1.sort()
        sage: L1
        [('b_1_0', b_1_0: 1-Cocycle in H^*(D8; GF(2))),
         ('b_1_0b_1_0', (b_1_0)*(b_1_0): 2-Cocycle in H^*(D8; GF(2))),
         ('b_1_0b_1_1', (b_1_0)*(b_1_1): 2-Cocycle in H^*(D8; GF(2))),
         ('b_1_1', b_1_1: 1-Cocycle in H^*(D8; GF(2))),
         ('b_1_1b_1_1', (b_1_1)*(b_1_1): 2-Cocycle in H^*(D8; GF(2))),
         ('c_2_2', c_2_2: 2-Cocycle in H^*(D8; GF(2)))]
        sage: H.exportMonomials()
        sage: H.Monomials={'bla':1}
        sage: H.importMonomials()
        sage: L2 = list(H.Monomials.items())
        sage: L2.sort()
        sage: L1 == L2
        True

  `filter_degree_type`()

    Return the filter degree type of `self`.

    OUTPUT:

    The filter degree type (list of integers) of a filter regular system of parameters of self, or `None`, if the cohomology computation is not finished yet.

    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: print(H.filter_degree_type())
        None
        sage: H.make()

    Since by default data are stored on disk, when we now compute the filter degree type (which in some cases is a very long computation!), the stored data are updated:

        sage: print(H.filter_degree_type())
        H^*(D8; GF(2)):
                  Updating stored data after computation of filter degree type
        [-1, -2, -2]

  `filter_regular_gready_parameters`(first_parameters=[], BreakPoint=None, ignore_nilpotent=True)

    Permanently cached method: Greadily explore smallest degree filter regular parameters.

    INPUT:

    - `first_parameters` (optional list) – list of strings defining some filter regular parameters that come after the Duflot elements

    - `BreakPoint` (optional integer) – maximal number of parameter candidates tested in each degree. Default `None` means unbounded.

    - `ignore_nilpotent` (optional bool, default True) – whether to ignore nilpotent generators in the enumeration of filter regular parameters; there are filter regular parameters that can be expressed without nilpotent generators, but we are not sure if the smallest degree parameters can be obtained in that way, too.

    OUTPUT:

    - A system of filter regular parameters.

    - The filter degree type is computed and stored. If the filter degree type of this ring has been computed before, it is asserted that the results are equal. Also it is tested whether the result contradicts the strong form of Dave Benson’s regularity conjecture.

    ..ALGORITHM:

        It is assumed that the completeness of the ring has already been proved.
        The function starts with a Duflot regular sequence and finds the
        new parameters by enumerating potential parameters in a greedy way.

    ..WARNING:

        We do not guarantee that this routine will always succeed, as we have
        no proof. However, on all groups of order 64 and 81, it works, and
        on about 10 percent of cases it yields filter regular parameters in
        smaller degrees than our previous methods.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()        # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(64,32,from_scratch=True)
        sage: H.make()
        sage: H.filter_regular_parameters()
        ['c_4_11',
         'b_1_1*b_3_6+b_1_1^4+b_2_3^2+b_2_2^2+b_2_1^2',
         'b_1_1^3*b_3_6+b_2_3^2*b_1_1^2+b_2_2*b_1_1*b_3_6+b_2_2*b_2_3^2+b_2_2^2*b_1_1^2+b_2_1*b_2_3^2',
         'b_1_1']

    So, we have parameters in degrees 4, 4, 6 and 1. Note that after computing the filter degree type, the ring is automatically stored, in order to preserve the result of this potentially very difficult computation (a warning is logged):

        sage: H.filter_degree_type()
        H^*(SmallGroup(64,32); GF(2)):
                  Updating stored data after computation of filter degree type
        [-1, -2, -3, -4, -4]

    We delete the previous result, compute filter regular parameters in degrees 4, 2, 2 and 1, and find that the filter degree type coincides with what was computed above:

        sage: H.delprop('fdt')
        sage: CohomologyRing.global_options('info')
        sage: H.filter_regular_gready_parameters()
        H^*(SmallGroup(64,32); GF(2)):
            Compute filter_regular_gready_parameters
            Computing quotient modulo Duflot regular sequence ['c_4_11']
            Exploring 2nd filter-regular parameter in degree 2
            Determine degree 2 standard monomials
        explore_one_parameter:
            8 = (2-1)^1*2^3 parameter candidates
            We found a parameter.
            > But it is not filter-regular.
            We found a parameter.
            > It is filter-regular.
        H^*(SmallGroup(64,32); GF(2)):
            Exploring 3rd filter-regular parameter in degree 2
            Determine degree 2 standard monomials
        explore_one_parameter:
            4 = (2-1)^1*2^2 parameter candidates
            We found a parameter.
            > It is filter-regular.
        H^*(SmallGroup(64,32); GF(2)):
            Exploring 4th filter-regular parameter in degree 2
            Determine degree 2 standard monomials
        explore_one_parameter:
            2 = (2-1)^1*2^1 parameter candidates
            We found a parameter.
            > It is filter-regular.
        ['c_4_11', 'b_2_2+b_2_1', 'b_2_3', 'b_1_1^2']
        sage: H.fdt
        [-1, -2, -3, -4, -4]

  `filter_regular_parameters`()

    Permanently cached method: Return elements of the ring approximation guaranteed to yield parameters in cohomology.

    OUTPUT:

    A list of strings, describing polynomials in `self`, or `None`.

    THEORY:

    (Powers of) Dickson elements in the polynomial part of the cohomology rings of maximal elementary abelian subgroups in a Sylow \(p\)-subgroup \(S\) of a finite group \(G\) give rise to a filter regular homogeneous system of parameters of the mod-\(p\) cohomology of \(G\) restricting to these Dickson elements, according to [Benson].

    The degree of these parameters may be very large. In [GreenKing], in the case that \(G=S\) is of prime power order, we propose to consider only Dickson elements in a complement of the greatest central elementary abelian subgroup \(C\) of \(S\) in the maximal abelian subgroups. We can show that these can be simultaneously lifted to cohomology elements of \(G\), to which we refer as the restricted Dickson elements. A filter regular hsop is then given by a maximal Duflot regular sequence, followed by the restricted Dickson elements. Moreover, parameters can be simplified by factorisation, potentially after adding a nilpotent element. This often yields fairly small parameters, but the factorisation may be quite difficult in some examples.

    In the case \(G\not=S\), it is in general impossible to lift a power of the Dickson elements in complements of \(C\). But if it is, the previous construction still yields a filter regular hsop. Therefore, we test whether the restricted Dickson elements of the cohomology of \(S\) happen to be stable. If they are, they yield a filter regular homogeneous system of parameters for the cohomology of \(S\), together with a Duflot regular sequence. A factorisation may further simplify the parameters.

    Moreover, in either case, the last parameter found by the above construction could be replaced by any other parameter of smaller degree. See `find_small_last_parameter()`

    EXAMPLES:

    Since we will access data from the cohomology of a subgroup, we will force its computation from scratch first:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: X = CohomologyRing(64,138,from_scratch=True)
        sage: X.make()
        sage: G = libgap.AlternatingGroup(8)
        sage: H = CohomologyRing(G,prime=2,GroupName='A8', from_scratch=True)

    We first demonstrate what happens in the cohomology ring of a sylow subgroup:

        sage: H.sylow_cohomology() is X
        True
        sage: H.sylow_cohomology().filter_regular_parameters()
        ['c_4_18', 'b_1_2^4+b_1_1^2*b_1_2^2+b_1_1^4+b_1_0^4+b_2_6^2+b_2_4*b_2_6+b_2_4^2', 'b_1_1^2*b_1_2^4+b_1_1^4*b_1_2^2+b_2_6^2*b_1_2^2+b_2_6^2*b_1_0^2+b_2_4*b_2_6*b_1_0^2+b_2_4*b_2_6^2+b_2_4^2*b_1_1*b_1_2+b_2_4^2*b_1_1^2+b_2_4^2*b_1_0^2+b_2_4^2*b_2_6', 'b_1_0']

    For computing the cohomology of \(G\), we use the cohomology ring of an intermediate subgroup. It turns out that a filter regular hsop for the cohomology ring of that subgroup can be found by using Dickson elements in a complement of the centre of a Sylow subgroup:

        sage: H.subgroup_cohomology()
        H^*(SmallGroup(192,1493); GF(2))
        sage: H.subgroup_cohomology().filter_regular_parameters()
        ['c_4_10', 'b_1_0^4+b_2_2^2+b_2_0*b_2_2+b_2_0^2', 'b_3_6^2+b_3_2*b_3_5+b_3_2^2+b_2_2^2*b_1_0^2+b_2_0*b_2_2*b_1_0^2+b_2_0*b_2_2^2+b_2_0^2*b_1_0^2+b_2_0^2*b_2_2', 'b_1_0']

    We try if we can do the same for the cohomology of \(G\):

        sage: H.make(8)
        sage: H.duflot_regular_sequence()
        ['c_4_1']
        sage: H.filter_regular_parameters()

    So, a maximal Duflot regular sequence is already available, but the remaining parameters are not. We compute out to degree 14 and then obtain filter regular parameters.

        sage: H.make(14)
        sage: H.filter_regular_parameters()
        ['b_3_1*b_5_2+b_2_0^4+c_4_1^2',
         'b_3_1^4+b_3_0^4+b_6_2*b_3_1^2+b_6_2^2+b_2_0^3*b_6_2+c_4_1*b_3_1*b_5_2+b_2_0*c_4_1*b_3_1^2+b_2_0^2*c_4_1^2',
         'b_7_6^2+b_3_1^3*b_5_2+b_6_2*b_3_1*b_5_2+b_2_0*b_6_2*b_3_1^2+b_2_0^3*b_3_1*b_5_2+b_2_0^4*b_6_2+b_2_0^2*c_4_1*b_3_1^2+b_2_0^2*c_4_1*b_6_2+c_4_1^2*b_3_0^2',
         'b_6_2']

  `find_dickson`()

    Temporarily cached method: Find classes of self that simultaneously restrict to the Dickson classes for special subgroups.

    NOTE:

    The method first checks if the current ring approximation contains parameters. If this is not the case (e.g., if a maximal Duflot regular sequence can not be found yet) then nothing is done. If Dickson invariants have been previously constructed (perhaps by a different method) then nothing is done as well.

    OUTPUT:

    The attribute `Dickson` (a list) is changed. The entries corresponding to factors of successfully lifted Dickson classes are strings that define a polynomial in the generators of self yielding the lift.

    If the group is not of prime power order, the restrictions of the parameters constructed by this method to any maximal elementary abelian subgroup in a Sylow subgroup are Dickson invariants.

    If the group is a \(p\)-group, the restrictions to a complement of the greatest central elementary abelian subgroup in any maximal elementary abelian subgroup are Dickson invariants.

    EXAMPLES:

    We use the option `useElimination`, in order to avoid that the Dickson classes will be lifted by a different method.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(64,33, useElimination=True, from_scratch=True)

    The group is of \(p\)-rank 3 and its center has rank 1. So, we will eventually get two Dickson classes:

        sage: H.pRank
        3
        sage: H.CenterRk
        1
        sage: H.Dickson
        [None, None]

    We try whether the Dickson classes can be lifted after computing the ring structure out to degree 2:

        sage: H.make(2)
        sage: H.find_dickson()
        False
        sage: H.Dickson
        [None, None]

    In degree 4, still nothing is done. This is since there is no Duflot regular sequence yet.

        sage: H.make(4)
        sage: H.find_dickson()
        False
        sage: H.Dickson
        [None, None]
        sage: H.duflot_regular_sequence()
        []

    We compute out to degree 8, since we happen to know that there is the Duflot regular generator waiting. When using `make()`, the Dickson invariants would be automatically determined. So, we work around.

        sage: H.make(7)
        sage: H.next()
        sage: H.Dickson
        [None, None]

    Now, we construct the Dickson elements manually, and find that indeed they could have been found in degree 4 already:

        sage: H.find_dickson()
        True
        sage: H.Dickson
        ['b_4_6+b_2_1^2', 'b_3_4+b_3_2']

  `find_dickson_in_subgroup`(n)

    If possible, return a lift of the Dickson classes (type <SingularElement> matrix) and the nil-radical (type <SingularElement> ideal) of the \(n\)-th special subgroup. Result is cached.

    EXAMPLES:

    We use the option `useElimination`, in order to avoid that the Dickson classes will be lifted by a different method.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(64,33, useElimination=True, from_scratch=True)
        sage: H.make(3)
        sage: H.find_dickson_in_subgroup(2)
        (None, None)
        sage: H.find_dickson_in_subgroup(3)
        (None, None)
        sage: H.make(4)
        sage: H.find_dickson_in_subgroup(2)
        (b_4_6+b_2_1^2,b_3_3, a_1_0,
        a_1_1,
        b_2_2,
        b_3_2,
        b_3_4+b_3_3,
        b_3_3^2+b_2_1*b_4_6,
        b_4_4^2+b_2_1^2*b_4_6)
        sage: H.find_dickson_in_subgroup(3)
        (b_4_6,b_3_4+b_3_2, a_1_0,
        a_1_1,
        b_2_1,
        b_3_3+b_3_2,
        b_4_4,
        b_3_2^2+b_2_2^3,
        b_3_4^2+b_2_2*b_4_6)

  `find_small_last_parameter`(Par, maxdeg=None)

    Permanently cached method: Find an element of smallest degree that can replace the last element of a given HSOP.

    INPUT:

    - `Par`: a list of parameters for the cohomology ring living in the current ring approximation, given by strings. The last entry may be `None`.

    - `maxdeg`: the maximal degree (int) in which a parameter will be sought. Default: The minimum of the degree of the current ring approximation and the degree of `P[-1]` (if not None) minus one.

    OUTPUT:

    Either a string defining a parameter in degree at most `maxdeg`, or `P[-1]` if such parameter does not exist. A value error is raised, if `Par[:-1]` can not be extended to a HSOP of the cohomology ring.

    THEORY:

    A set \(P\) of elements of the ring approximation provides parameters for the cohomology ring if and only if the cohomology rings of all maximal elementary abelian subgroups are finite over the restrictions of \(P\). If the ring approximation is lacking relations in higher degrees, then \(P\) is not necessarily a hsop for the approximation as well.

    We obtain \(P'\) from \(P\) by replacing the last parameter with a parameter of smallest degree, that is obtained by enumeration of elements in small degrees.

    If \(P\) is filter regular then so is \(P'\), which is proved in [GreenKing].

    NOTE:

    In each degree, a default of at most 512 candidates are tested; this default can be altered by assigning a value to `pGroupCohomology.resolution.coho_options['NrCandidates']`. The reason for setting the default to such a small number is that both in the modified Benson criterion and in the Hilbert-Poincaré criterion we can do with an existence proof for parameters. So, it is normally not crucial to have a very small last parameter (though it may simplify the test for filter regularity).

    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(1)
        sage: print(H)
        Cohomology ring of Dihedral group of order 8 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 1
        Minimal list of generators:
        [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:
        []

    Hence, the ring approximation has a hsop formed by the two generators. But the method realises that this would not yield parameters for the cohomology and consequently raises an error:

        sage: H.find_small_last_parameter(['b_1_0', None])
        Traceback (most recent call last):
        ...
        ValueError: The input can not be extended to a hsop

    Later it will turn out that the sum of the degree one generators, together with a generator in degree two, forms a homogeneous system of parameters. The program can verify it by restriction to maximal elementary abelian subgroups, and so the error vanishes. But we only know the ring out to degree one, and so we still don’t find a second parameter:

        sage: P = ['b_1_0 + b_1_1', None]
        sage: print(H.find_small_last_parameter(P))
        None

    Computing one degree further, we have success:

        sage: H.next()
        sage: CohomologyRing.global_options('info')
        sage: P[-1] = H.find_small_last_parameter(P); P[-1]
        H^*(D8; GF(2)):
            Compute find_small_last_parameter
            Computing complete Groebner basis
            Compute _parameter_restrictions
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            Compute restricted parameters
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            Compute restricted parameters
        H^*(D8; GF(2)):
            Compute _get_obvious_parameter
            Compute _parameter_restrictions
            compute radicals of restricted parameter ideal
            Compute _parameter_restrictions
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            Compute restricted parameters
        Induced homomorphism of degree 0 from H^*(D8; GF(2)) to H^*(SmallGroup(4,2); GF(2)):
            Compute restricted parameters
        H^*(D8; GF(2)):
            Determine degree 1 standard monomials
            Compute _get_obvious_parameter
            Determine degree 2 standard monomials
            --> Last parameter found in degree 2
        'c_2_2'

    Let us verify that the two elements form a filter regular hsop:

        sage: H.raw_filter_degree_type(P)
            Compute raw_filter_degree_type
            Test filter regularity
              Filter degree type: [-1, -2, -2]
        ([-1, -1, 1], [[0], [0], [1, 1]], [1, 2])
        sage: CohomologyRing.global_options('warn')

  `fraction_field`()

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()
        sage: H = CohomologyRing(8,3)
        sage: H.fraction_field()
        Traceback (most recent call last):
        ...
        TypeError: A cohomology ring is, in general, not an integral domain.

  `from_base_ring`(r)

    Return a degree zero cohomology class.

    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.from_base_ring(GF(2)(1))
        1: 0-Cocycle in H^*(D8; GF(2))

  `gen`(i)

    Return generators 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()

    Generator number zero is 1 in the base ring of `H`:

        sage: H.0
        1
        sage: H.1     # indirect doctest
        c_2_2: 2-Cocycle in H^*(D8; GF(2))
        sage: H.2
        b_1_0: 1-Cocycle in H^*(D8; GF(2))
        sage: print(H.1*H.2)
        3-Cocycle in H^*(D8; GF(2)),
        represented by
        [0 0 1 0]

  `gens`()

    Return the list of generators of `self`.

    NOTE:

    We consider the scalar `1` as a generator. The list of generators may change if an incomplete cohomology computation is continued.

    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(1)
        sage: H.gens()
        [1, b_1_0: 1-Cocycle in H^*(D8; GF(2)), b_1_1: 1-Cocycle in H^*(D8; GF(2))]
        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))]

  `group`()

    Return the group over which `self` is defined, as a permutation group.

    OUTPUT:

    Let \(G\) be the group for which self is defined. Recall that in the case of prime power groups it is assumed that the first, say \(n\), generators of \(G\) form a minimal generating set. Then, the output of `group()` is a permutation group \(G_P\), defined in the libgap interface, with precisely \(n\) generators, so that mapping generator \(i\) of \(G\) to generator \(i\) of \(G_P\), for \(i=1,...,n\), results in a group isomorphism-

    NOTE:

    `CohomologyRing(self.group())` is always equal to `self`. It is often even identical with `self`, namely if the Small Groups address can be determined, as in the following example.

    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: G = H.group()
        sage: G
        Group([ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ])
        sage: H1 = CohomologyRing(G, GroupName='NewD8')
        sage: H is H1
        True

  `group_is_abelian`()

    Permanently cached method: Tell whether the associated group is abelian.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: CohomologyRing(8,3).group_is_abelian()
        False
        sage: CohomologyRing(8,2).group_is_abelian()
        True

  `hom`(m, other, M=None, d=0)

    Create an induced homomorphism.

    INPUT:

    - `m`, which usually is a group homomorphism defined in the libgap interface, but in principle could also be a `Matrix_gfpn_dense` matrix describing a homomorphism of the group algebras (not documented). The domain must be equivalent to the underlying group of `other`, the codomain must be equivalent to the underlying group of `self`.

    - `other`, a cohomology ring

    - `M` (optional `Matrix_gfpn_dense` matrix): By this matrix one could prescribe a mapping of the first terms of the respective resolutions (not documented, and not needed for induced maps of group homomorphisms).

    - `d` (optional, default 0): Degree of the map. If it is non-zero then `M` must be provided.

    NOTE:

    The resulting homomorphism is cached.

    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)
        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,5)(2,6)(3,8)(4,7), (1,8)(2,7)(3,6)(4,5) ] )')
        sage: H1.group()==phi.Source()
        True
        sage: H2.group().canonicalIsomorphism(phi.Range()) != libgap.eval('fail')
        True
        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)
        sage: phi_star
        phi^*
        sage: phi_star.domain()
        H^*(DihedralGroup(8); GF(2))
        sage: phi_star.codomain()
        H^*(D8; GF(2))
        sage: [H1.element_as_polynomial(phi_star(X)) for X in H2.gens()]
        [1: 0-Cocycle in H^*(D8; GF(2)),
         b_1_1^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_1: 1-Cocycle in H^*(D8; GF(2))]

    The induced maps are cached:

        sage: phi_star is H2.hom(phi,H1)
        True
        sage: phi_star is loads(dumps(phi_star))
        True

    Cohomology rings of prime power and non prime power groups can be freely combined. We compute the mod-2 cohomology ring of some group of order 48. The ring presentation depends on the choice of a generating system for its Sylow 2-subgroup. Since an internal computation would yield a randomised result, we provide a Sylow 2-subgroup explicitly.

        sage: G = libgap.SmallGroup(48,36)
        sage: g1,g2,g3,g4,g5 = G.GeneratorsOfGroup()
        sage: S = g1.Group(g1*g2*g3,g2,g4)
        sage: HG = CohomologyRing(G,prime=2,Subgroup=S,GroupName='SmallGroup(48,36)', from_scratch=True)
        sage: HG.make()

    There is an embedding of the dihedral group into `G`, and a quotient of `G` is isomorphic to the dihedral group.

        sage: G1toG = G1.GroupHomomorphismByImages(G, G1.GeneratorsOfGroup(), [g1*g2,g1*g2*g3,g4])
        sage: g11,g12,g13 = G1.GeneratorsOfGroup()
        sage: GtoG1 = G.GroupHomomorphismByImages(G1, G.GeneratorsOfGroup(),[g12*g13,g13,g11*g12,g13,G1.Identity()])
        sage: GtoG1.Image().IdGroup()
        [ 8, 3 ]
        sage: G1toG.Image().IdGroup()
        [ 8, 3 ]
        sage: GtoG1_star = H1.hom(GtoG1,HG)
        sage: G1toG_star = HG.hom(G1toG,H1)
        sage: [H1.element_as_polynomial(G1toG_star(x)) for x in HG.gens()]
        [1: 0-Cocycle in H^*(D8; GF(2)), 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)), b_1_0: 1-Cocycle in H^*(D8; GF(2))]
        sage: [HG.element_as_polynomial(GtoG1_star(x)) for x in H1.gens()[1:]]
        [b_1_1*c_1_2+b_1_0*c_1_2+c_2_5+c_1_2^2: 2-Cocycle in H^*(SmallGroup(48,36); GF(2)), b_1_1: 1-Cocycle in H^*(SmallGroup(48,36); GF(2)), b_1_0: 1-Cocycle in H^*(SmallGroup(48,36); GF(2))]

    And finally, we consider a homomorphism from `G` to `G`, by composition of the previous homomorphisms:

        sage: GtoG = G1toG.CompositionMapping(GtoG1)
        sage: GtoG_star = HG.hom(GtoG,HG)
        sage: [HG.element_as_polynomial(GtoG_star(x)) for x in HG.gens()[1:]]
        [b_1_1*c_1_2+b_1_0*c_1_2+c_2_5+c_1_2^2: 2-Cocycle in H^*(SmallGroup(48,36); GF(2)), b_1_1: 1-Cocycle in H^*(SmallGroup(48,36); GF(2)), b_1_0: 1-Cocycle in H^*(SmallGroup(48,36); GF(2)), b_1_1: 1-Cocycle in H^*(SmallGroup(48,36); GF(2))]

    `GtoG` should coincide with the composition of the previous two induced homomorphisms, and indeed it does:

        sage: GtoG1_star*G1toG_star == GtoG_star
        True

  `htmlpage`(user=None)

    Create a html page describing `self`

    OUTPUT:

    A html file describing the cohomology ring `H` is written to `os.path.join(H.root,repr(H.group().Order()),'web',H.GStem+'.html')`

    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: H.htmlpage()
        sage: import os
        sage: print(open(os.path.join(H.root,'%dweb'%H.group().Order(),H.GStem+'.html')).read())
        <html>
        <head>
        <title>Cohomology of Group number 3 of Order 8
        </title>
            <!--#config timefmt="%d.%m.%Y" -->
        </head>
        <body>
        <BLANKLINE>
          <a name = "general"></a><h2>
          Cohomology of group number 3 of order 8
        </h2>
        <p>
        <table border="1">
          <tr>
            <td><a href="#general">About the group</a></td>
            <td><a href="#generators">Ring generators</a></td>
            <td><a href="#relations">Ring relations</a></td>
            <td><a href="#completion">Completion information</a></td>
            <td><a href="#restrict">Restriction maps</a></td>
          </tr>
        </table>
        <BLANKLINE>
        <p><hr></p>
        <h3>
          General information on the group
        </h3>
        <p><ul>
          <li> The group is also known as D8, the Dihedral group of order 8.
          </li>
          <li>The group has 2 minimal generators and exponent 4.
          </li>
          <li> It is non-abelian.
          </li>
          <li> It has p-Rank 2.
          </li>
          <li> Its centre has rank 1.
          </li>
          <li> It has 2 conjugacy classes of maximal elementary abelian subgroups, which are all of rank 2.
          </li>
        </ul></p>
        <p><hr></p>
        <h3>
          Structure of the cohomology ring
        </h3>
        <h4>
          General information
        </h4>
        <p><ul>
          <li> The cohomology ring is of dimension 2 and depth 2.
          </li>
          <li> The depth exceeds the Duflot bound, which is 1.
          </li>
          <li> The Poincar&eacute; series is    <table style="color:black"><tr><td align="center"><nobr>1</nobr></td></tr>      <tr><td><hr style="color:black"></td></tr><tr><td align="center"><nobr>(&thinsp;&#8722;&thinsp;1 &thinsp;+&thinsp; t)<sup>2</sup></nobr></td></tr>
            </table>
          </li>  <li> The a-invariants are -&infin;,-&infin;,-2.  They were obtained using the filter regular HSOP of the <a href="#completion">Symonds test</a>.
          </li>
          <li> The filter degree type of any filter regular HSOP is [-1, -2, -2].
          </li>
        </ul></p>
        <BLANKLINE>
        <BLANKLINE>
          <a name = "generators"></a>
          <p>
        <table border="1">
          <tr>
            <td><a href="#general">About the group</a></td>
            <td><a href="#generators">Ring generators</a></td>
            <td><a href="#relations">Ring relations</a></td>
            <td><a href="#completion">Completion information</a></td>
            <td><a href="#restrict">Restriction maps</a></td>
          </tr>
        </table></p>
        <BLANKLINE>
        <h4>
          Ring generators
        </h4>
         <p>The cohomology ring has 3 minimal generators of maximal degree 2:
        </p>
        <ol>
          <li> <nobr>b_1_1</nobr>, an element of degree 1
          </li>
          <li> <nobr>b_1_0</nobr>, an element of degree 1
          </li>
          <li> <nobr>c_2_2</nobr>, a Duflot element of degree 2
          </li>
        </ol>
        <BLANKLINE>
        <a name = "relations"></a>
          <p>
        <table border="1">
          <tr>
            <td><a href="#general">About the group</a></td>
            <td><a href="#generators">Ring generators</a></td>
            <td><a href="#relations">Ring relations</a></td>
            <td><a href="#completion">Completion information</a></td>
            <td><a href="#restrict">Restriction maps</a></td>
          </tr>
        </table></p>
        <BLANKLINE>
        <h4>
          Ring relations
        </h4>
        <p>There is one minimal relation of degree 2:
        <ol>
          <li> <nobr>b_1_0&middot;b_1_1</nobr>
          </li>
        </ol></p>
        <BLANKLINE>
        <a name = "completion"><p><hr></p></a>
          <p>
        <table border="1">
          <tr>
            <td><a href="#general">About the group</a></td>
            <td><a href="#generators">Ring generators</a></td>
            <td><a href="#relations">Ring relations</a></td>
            <td><a href="#completion">Completion information</a></td>
            <td><a href="#restrict">Restriction maps</a></td>
          </tr>
        </table></p>
        <BLANKLINE>
        <h3>
          Data used for the Symonds test
        </h3>
        <p>
          <ul>
            <li> We proved completion in degree 2 using the Symonds criterion.
            </li>
            <li> The completion test was perfect: It applied in the last degree in which a generator or relation was found.
            </li>
            <li> The following is a filter regular homogeneous system of parameters:
            <ol>
              <li><nobr>c_2_2</nobr>, an element of degree 2
              </li>
              <li><nobr>b_1_1&thinsp;+&thinsp;b_1_0</nobr>, an element of degree 1
              </li>
            </ol>
            </li>    <li> A Duflot regular sequence is given by <nobr>c_2_2</nobr>.
            </li>
            <li> The Raw Filter Degree Type of the filter regular HSOP is [-1, -1, 1].
            </li>
            <li> We used the following parameters for the Symonds criterion:
            </li>
            <ol>
              <li><nobr>b_1_0</nobr>, an element of degree 1
              </li>
              <li><nobr>b_1_1</nobr>, an element of degree 1
              </li>
              <li><nobr>c_2_2</nobr>, an element of degree 2
              </li>
            </ol>
            </li>    <li> As a module over these parameters, the cohomology is generated in degree at most 0.
            </li>
          </ul></p>
        <p><a name="restrict"><hr></a></p>
        <p>
        <table border="1">
          <tr>
            <td><a href="#general">About the group</a></td>
            <td><a href="#generators">Ring generators</a></td>
            <td><a href="#relations">Ring relations</a></td>
            <td><a href="#completion">Completion information</a></td>
            <td><a href="#restrict">Restriction maps</a></td>
          </tr>
        </table></p>
        <BLANKLINE>
        <h3>
          Restriction maps
        </h3>
          <h4>
            Restriction map to the greatest central el. ab. subgp., which is of rank 1
          </h4>
            <ol>
              <li> <nobr>b_1_1</nobr> &rarr; <nobr>0</nobr>, an element of degree 1
              </li>
              <li> <nobr>b_1_0</nobr> &rarr; <nobr>0</nobr>, an element of degree 1
              </li>
              <li> <nobr>c_2_2</nobr> &rarr; <nobr>c_1_0<sup>2</sup></nobr>, an element of degree 2
              </li>
            </ol>
        <BLANKLINE>
          <h4>
            Restriction map to a maximal el. ab. subgp. of rank 2
          </h4>
            <ol>
              <li> <nobr>b_1_1</nobr> &rarr; <nobr>c_1_1</nobr>, an element of degree 1
              </li>
              <li> <nobr>b_1_0</nobr> &rarr; <nobr>0</nobr>, an element of degree 1
              </li>
              <li> <nobr>c_2_2</nobr> &rarr; <nobr>c_1_0&middot;c_1_1&thinsp;+&thinsp;c_1_0<sup>2</sup></nobr>, an element of degree 2
              </li>
            </ol>
        <BLANKLINE>
          <h4>
            Restriction map to a maximal el. ab. subgp. of rank 2
          </h4>
            <ol>
              <li> <nobr>b_1_1</nobr> &rarr; <nobr>0</nobr>, an element of degree 1
              </li>
              <li> <nobr>b_1_0</nobr> &rarr; <nobr>c_1_1</nobr>, an element of degree 1
              </li>
              <li> <nobr>c_2_2</nobr> &rarr; <nobr>c_1_0&middot;c_1_1&thinsp;+&thinsp;c_1_0<sup>2</sup></nobr>, an element of degree 2
              </li>
            </ol>
        <BLANKLINE>
        <p><hr></p>
        <p>
        <table border="1">
          <tr>
            <td><a href="#general">About the group</a></td>
            <td><a href="#generators">Ring generators</a></td>
            <td><a href="#relations">Ring relations</a></td>
            <td><a href="#completion">Completion information</a></td>
            <td><a href="#restrict">Restriction maps</a></td>
          </tr>
        </table></p>
        <BLANKLINE>
        <BLANKLINE>
                      <br clear="all">
                      <P>
                      <HR WIDTH="100%">
                      <HR WIDTH="100%"></P>
                      Created with the <a href="http://www.sagemath.org/" style="font-variant:small-caps">Sage</a>
                      <a href="https://users.fmi.uni-jena.de/cohomology/documentation/">cohomology package</a>
                      written by <a href="https://users.fmi.uni-jena.de/~king/">Simon King</a>
                      and <a href="https://users.fmi.uni-jena.de/~green/">David Green</a>
                      <P>
                      <HR WIDTH="100%">
                      <HR WIDTH="100%"></P>
              <p>
              <i>Last change: <!--#echo var="LAST_MODIFIED" --></i>
              <hr>
        <BLANKLINE>
                </BODY>
                </HTML>
        <BLANKLINE>

  `importMonomials`()

    Reload previously exported standard monomials.

    NOTE:

    This method is used when reloading a cohomology ring. There is no need to ever call this method explicitly, so, the following is not a use case.

    The method requires that the dictionary self.Monomials has the key `'bla'`. Otherwise, the monomials, that are stored in some standard location, will not be reloaded.

    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: L1 = list(H.Monomials.items())
        sage: L1.sort()
        sage: L1
        [('b_1_0', b_1_0: 1-Cocycle in H^*(D8; GF(2))),
         ('b_1_0b_1_0', (b_1_0)*(b_1_0): 2-Cocycle in H^*(D8; GF(2))),
         ('b_1_0b_1_1', (b_1_0)*(b_1_1): 2-Cocycle in H^*(D8; GF(2))),
         ('b_1_1', b_1_1: 1-Cocycle in H^*(D8; GF(2))),
         ('b_1_1b_1_1', (b_1_1)*(b_1_1): 2-Cocycle in H^*(D8; GF(2))),
         ('c_2_2', c_2_2: 2-Cocycle in H^*(D8; GF(2)))]
        sage: H.Monomials={'bla':1}

    Since, by default, the cohomology ring was automatically saved, the monomials are available in some file. So, we can import them:

        sage: H.importMonomials()
        sage: L2 = list(H.Monomials.items())
        sage: L2.sort()
        sage: L2 == L1
        True

  `is_isomorphic`(other)

    Test whether two cohomology rings are isomorphic as graded rings.

    INPUT:

    - `other`, a cohomology ring

    OUTPUT:

    - False, if self is not isomorphic to the given other cohomology ring.

    - None, if no conclusion on the isomorphy could be obtained.

    - A tuple of strings defining the generator images in an isomorphism from self to other.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()
        sage: H173 = CohomologyRing(64, 173)
        sage: H176 = CohomologyRing(64, 176)
        sage: H173.make()
        sage: H176.make()

    The rings are similar, but not identical:

        sage: H173.rels()
        ['a_1_1*b_1_0+a_1_1^2',
         'b_1_2^2+b_1_0*b_1_2',
         'a_1_1^3',
         'a_1_1*b_3_6',
         'b_3_6^2+b_1_0^3*b_3_6+c_4_9*b_1_0^2+c_4_9*a_1_1^2']
        sage: H176.rels()
        ['a_1_1*b_1_0+a_1_1^2',
         'b_1_2^2+b_1_0*b_1_2',
         'a_1_1^3',
         'a_1_1*b_3_6',
         'b_3_6^2+b_1_0^2*b_1_2*b_3_6+b_1_0^3*b_3_6+c_4_9*b_1_0^2+c_2_4*b_1_0^3*b_1_2+c_4_9*a_1_1^2']

    The existence of an isomorphism will be determined by an enumeration of all possible ways to map the generators of the first ring to elements of the second ring. This would of course be a huge number, but it can be cut down by various tests (for instance, the ideal generated by the generator images need to have the same Poincaré series than the ideal generated by the mapped generators, and in some cases it is also helpful to take the Poincaré series of annihilators of ideals into account). Often, there only remains a single possibility to map some of the generators in a way that could potentially extend to an isomorphism.

    In an attempt to keep the average computation time small, the number of possible assignments tested is cut off. If no conclusion can be made from these tests, then the cut-off is automatically adapted until a conclusion can be achieved:

        sage: H173.is_isomorphic(H176)              # long time
        ('1*c_2_4',
         '1*b_1_2*b_3_6+1*c_4_9+1*c_2_4*b_1_0*b_1_2',
         '1*a_1_1',
         '1*b_1_0',
         '1*b_1_2',
         '1*b_3_6')

    We now demonstrate that even fairly similar cohomology rings can be shown to be non-isomorphic. In the following example, the Poincaré series, the generator degrees and the degrees of minimal relations coincide.

        sage: H85 = CohomologyRing(64, 85)
        sage: H85.make()
        sage: H85.poincare_series() == H173.poincare_series()
        True
        sage: H85.degvec == H173.degvec
        True
        sage: H85.rels()
        ['a_1_0^2', 'a_1_1^2', 'a_1_0*b_1_2^2', 'a_1_0*a_3_6', 'a_3_6^2']
        sage: H173.rels()
        ['a_1_1*b_1_0+a_1_1^2',
         'b_1_2^2+b_1_0*b_1_2',
         'a_1_1^3',
         'a_1_1*b_3_6',
         'b_3_6^2+b_1_0^3*b_3_6+c_4_9*b_1_0^2+c_4_9*a_1_1^2']
        sage: CohomologyRing.global_options('info')
        sage: H85.is_isomorphic(H173)
        IsomorphismTest(H^*(SmallGroup(64,85); GF(2)), H^*(SmallGroup(64,173); GF(2))):
            Trying to find an isomorphism
        H^*(SmallGroup(64,85); GF(2)):
            Inserting SmallGroup(4,2) as a subgroup
            Inserting SmallGroup(8,5) as a subgroup
            Reconstructing subgroup data
        H^*(SmallGroup(64,173); GF(2)):
            Determine degree 1 standard monomials
        IsomorphismTest(H^*(SmallGroup(64,85); GF(2)), H^*(SmallGroup(64,173); GF(2))):
            gen(5) is rigid: b_1_2 --> 1*b_1_0
        H^*(SmallGroup(64,173); GF(2)):
            Determine degree 1 standard monomials
        IsomorphismTest(H^*(SmallGroup(64,85); GF(2)), H^*(SmallGroup(64,173); GF(2))):
            There cannot be a homomorphism, (gen(3)) cannot be mapped
            There cannot be a homomorphism, (gen(3)) cannot be mapped
            There cannot be a homomorphism, (gen(3)) cannot be mapped
            There cannot be a homomorphism, (gen(3)) cannot be mapped
            There is definitely no isomorphism
        False

  `item2html`(x)

    Return a string that provides HTML code for the input.

    INPUT:

    Any object; but its intended use is for cohomology elements or for strings defining a polynomial.

    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.item2html(H.1)
        '<nobr>c_2_2</nobr>, a Duflot element of degree 2'
        sage: H.item2html(H.2*H.1^2)
        '<nobr>c_2_2<sup>2</sup>&middot;b_1_0</nobr>, an element of degree 5'
        sage: H.item2html(H.poincare_series())
        '<nobr>1/(t<sup>2 </sup>&thinsp;&#8722;&thinsp; 2&middot;t &thinsp;+&thinsp; 1)</nobr>'

  `label`()

    Provide a short description of this cohomology ring.

    NOTE:

    In some cases, this is equal to the string representation.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.label()
        'H^*(8gp3; GF(2))'
        sage: H
        H^*(D8; GF(2))
        sage: H = CohomologyRing(64,167)
        sage: H
        H^*(SmallGroup(64,167); GF(2))
        sage: H.label()
        'H^*(64gp167; GF(2))'

  `last_interesting_degree`()

    Presentation degree of the current ring approximation.

    OUTPUT:

    The highest degree of a generator or relation in the current ring approximation.

    EXAMPLE:

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

    In our example, we compute the mod-2 cohomology of the Mathieu group \(M_{11}\).

        sage: G = libgap.MathieuGroup(11)
        sage: H = CohomologyRing(G,prime=2,GroupName='M11', from_scratch=True)

    The smallest generator is in degree three, so, we have:

        sage: H.make(2)
        sage: H.last_interesting_degree()
        0

    The generator of highest degree is in degree 5, and there is no relation before degree 10. Hence, we obtain:

        sage: H.make(9)
        sage: H.last_interesting_degree()
        5

    We now finish the cohomology computation.

        sage: H.make()
        sage: H.last_interesting_degree()
        10
        sage: print(H)
        Cohomology ring of M11 with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [c_4_0: 4-Cocycle in H^*(M11; GF(2)),
         b_3_0: 3-Cocycle in H^*(M11; GF(2)),
         b_5_0: 5-Cocycle in H^*(M11; GF(2))]
        Minimal list of algebraic relations:
        [b_5_0^2+c_4_0*b_3_0^2]

  `lift_dickson`(i, j)

    Try to lift some power of some Dickson class.

    INPUT:

    - \(i = 0, 1, 2, ...\) - indicates which Dickson class of the maximal elementary abelian subgroups ought to be lifted.

    - \(j = 0, 1, 2, ...\) - indicates which power of that Dickson class ought to be lifted.

    OUTPUT:

    If the underlying group is a finite \(p\)-group then let \(n=p^j\), otherwise let \(n=j\). If it is possible to find a cochain of self that simultaneously restricts to the \(n\)-th power of the \(i\)-th Dickson classes of all maximal elementary abelian subgroups, potentially modified by nilpotent classes, then this cochain is returned.

    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: print(H.lift_dickson(0,0))
        1-Cocycle in H^*(D8; GF(2)),
        represented by
        [1 1]
        sage: print(H.lift_dickson(0,1))
        2-Cocycle in H^*(D8; GF(2)),
        represented by
        [1 1 0]

    Indeed, the restrictions of these classes to the two maximal elementary abelian subgroups coincides with their Dickson classes, respectively the square of the Dickson classes:

        sage: H.subgpDickson[4,2][0] == H.restriction_maps()[2][1](H.lift_dickson(0,0))
        True
        sage: H.subgpDickson[4,2][0] == H.restriction_maps()[3][1](H.lift_dickson(0,0))
        True
        sage: H.subgpDickson[4,2][0]**2 == H.restriction_maps()[2][1](H.lift_dickson(0,1))
        True
        sage: H.subgpDickson[4,2][0]**2 == H.restriction_maps()[3][1](H.lift_dickson(0,1))
        True

  `make`(max_deg=- 1)

    Construct the visible ring structure.

    INPUT:

    - `max_deg` (optional positive integer): compute the complete ring structure at most up to degree `max_deg`. The default is a complete computation.

    TESTS:

    We first create a cohomology ring.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(32,5, from_scratch=True)
        sage: H.make(2)
        sage: print(H)
        Cohomology ring of Small Group number 5 of order 32 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 2
        Minimal list of generators:
        [a_2_1: 2-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         c_2_2: 2-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         c_2_3: 2-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         a_1_0: 1-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         b_1_1: 1-Cocycle in H^*(SmallGroup(32,5); GF(2))]
        Minimal list of algebraic relations:
        [a_1_0^2,
         a_1_0*b_1_1]
        sage: H.make()
        sage: print(H)
        Cohomology ring of Small Group number 5 of order 32 with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [a_2_1: 2-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         c_2_2: 2-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         c_2_3: 2-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         a_1_0: 1-Cocycle in H^*(SmallGroup(32,5); GF(2)),
         b_1_1: 1-Cocycle in H^*(SmallGroup(32,5); GF(2))]
        Minimal list of algebraic relations:
        [a_1_0^2,
         a_1_0*b_1_1,
         a_2_1*a_1_0,
         a_2_1^2]

  `make_groebner`(d=0)

    Compute a Groebner basis for the relation ideal.

    INPUT:

    `d`: (optional) degree bound. Default: no degree bound

    NOTE:

    We keep track up to what degree a Groebner basis for the relation ideal is known. Hence, calling `make_groebner()` twice would only result in a re-computation if the relation ideal has changed in the meantime.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(27,3, from_scratch=True)
        sage: H.make(3)
        sage: CohomologyRing.global_options('info')
        sage: len(H.RelG)
        5
        sage: H.make_groebner(5)
        H^*(E27; GF(3)):
            Computing Groebner basis up to degree 5
        sage: len(H.RelG)
        8
        sage: H.make_groebner()
            Computing complete Groebner basis

    Since the Groebner basis is already completely known, it is avoided to repeat the computation when we now request a Groebner basis out to degree at least 5, which can be seen by the absence of any log messages:

        sage: H.make_groebner(5)

  `massey_products`(all=True, *L)

    All possible elements of `self` that realize the Massey product of the given input.

    INPUT:

    - `C_1,C_2,...`: Elements of the cohomology ring.

    - `all` (optional, default `True`): If it is `False`, a set containing at most one cocycle is returned.

    OUTPUT:

    The set valued Massey product of `C_1,C_2,...`

    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.2
        b_1_0: 1-Cocycle in H^*(D8; GF(2))
        sage: H.3
        b_1_1: 1-Cocycle in H^*(D8; GF(2))
        sage: H.rels()
        ['b_1_0*b_1_1']

    Since the product of `H.2` and `H.3` vanishes, we can compute some triple Massey products, transforming the result into a sorted list for having reproducible doc tests:

        sage: sorted(list(H.massey_products(H.2,H.3,H.2)))
        [0: 2-Cocycle in H^*(D8; GF(2)), b_1_0^2: 2-Cocycle in H^*(D8; GF(2))]
        sage: sorted(list(H.massey_products(H.3,H.2,H.3)))
        [0: 2-Cocycle in H^*(D8; GF(2)), b_1_1^2: 2-Cocycle in H^*(D8; GF(2))]

    Here is another example, for testing against a bug that occurred in a previous version of the code:

        sage: H = CohomologyRing(16,2)
        sage: H.make()
        sage: sorted(list(H.massey_products(H.3*H.1,H.3,H.3*H.1)))
        [0: 6-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_2_1*c_2_2*c_1_0*c_1_1: 6-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_2_1^2*c_1_0*c_1_1: 6-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_2_1*c_2_2*c_1_0*c_1_1+c_2_1^2*c_1_0*c_1_1: 6-Cocycle in H^*(SmallGroup(16,2); GF(2))]

    If one is interested in only one element of the Massey product, one can use the optional parameter `all=False`:

        sage: H.massey_products(H.3*H.1,H.3,H.3*H.1,H.3*H.1, all=False)
        {c_2_1^4: 8-Cocycle in H^*(SmallGroup(16,2); GF(2))}

    There are various results on Massey products that can be used for testing our computations. We give one explicit computation in the documentation of `massey_power()`. Here, we test against a part of the Juggling Theorem (see [Ravenel] Section A1.4) that states

    > \(\langle c_1,c_2,...,c_n\rangle c \subset \langle c_1,c_2,...,c_{n-1},c_nc\rangle,\)

    where \(c,c_1,...,c_n\) are cocycles, and the multiplication on the left hand side is taken element-wise. For our example, we use the extraspecial 3-group of order 27 and exponent 3:

        sage: H = CohomologyRing(27,3)
        sage: H.make()
        sage: H.gens()
        [1, b_2_0: 2-Cocycle in H^*(E27; GF(3)), b_2_1: 2-Cocycle in H^*(E27; GF(3)), b_2_2: 2-Cocycle in H^*(E27; GF(3)), b_2_3: 2-Cocycle in H^*(E27; GF(3)), c_6_8: 6-Cocycle in H^*(E27; GF(3)), a_1_0: 1-Cocycle in H^*(E27; GF(3)), a_1_1: 1-Cocycle in H^*(E27; GF(3)), a_3_4: 3-Cocycle in H^*(E27; GF(3)), a_3_5: 3-Cocycle in H^*(E27; GF(3))]
        sage: H.massey_products(H.6,H.6,H.6,all=False)
        {-b_2_0: 2-Cocycle in H^*(E27; GF(3))}
        sage: H.massey_products(H.6,H.6,H.6*H.5,all=False)
        {-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))}

    Note that there is the summand `-b_2_0*c_6_8` that we would expect. There remains to show that the other summands belong to the indeterminacy of the Massey product. More precisely, we show that `-b_2_0^2*a_1_1*a_3_5+b_2_0^2*a_1_0*a_3_5` is a multiple of `H.6`:

        sage: H.6*(2*H.8*H.2*H.2+2*H.8*H.1*H.2 + H.1^2*H.9) == H('-b_2_0^2*a_1_1*a_3_5+b_2_0^2*a_1_0*a_3_5')
        True

    Hence, `H.massey_products(H.6,H.6,H.6*H.5)` contains `-b_2_0*c_6_8`.

  `next`(Forced=False, KeepDecomposables=False)

    Compute generators and relations up to the next unknown degree.

    TESTS:

    We first create a cohomology ring.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3, useElimination=True, from_scratch=True)
        sage: print(H)
        Cohomology ring of Dihedral group of order 8 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 0
        Minimal list of generators:
        []
        Minimal list of algebraic relations:
        []
        sage: H.next()
        sage: print(H)
        Cohomology ring of Dihedral group of order 8 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 1
        Minimal list of generators:
        [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:
        []
        sage: H.next()
        sage: print(H)
        Cohomology ring of Dihedral group of order 8 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 2
        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]

  `ngens`()

    Return the number of generators of `self`.

    NOTE:

    We consider the scalar `1` as a generator.

    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.ngens()
        4
        sage: len(H.gens())
        4

  `nil_preimage`(n)

    Temporarily cached method: Preimage of the nil-radical of the \(n\)-th special subgroup.

    INPUT:

    - `n`: an integer indicating a special subgroup

      - `n=1` refers to the greatest central elementary abelian subgroup

      - `n>1` refers to a representative of conjugacy classes of maximal elementary abelian subgroups

    OUTPUT:

    An ideal in the Singular interface. It corresponds to the preimage of the nil radical of the cohomology of the \(n\)-th special subgroup.

    EXAMPLES:

    We need to choose a \(p\)-group with \(p>2\), since we would like to have an example where the cohomology of elementary abelian groups has non-trivial nil radical.

        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: H.nil_preimage(2)
        a_1_0,
        a_1_1,
        b_2_0,
        b_2_1,
        b_2_2,
        a_3_4,
        a_3_5
        sage: _.parent()
        Singular
        sage: H.nil_preimage(3)
        a_1_0,
        a_1_1,
        b_2_1,
        b_2_2,
        b_2_3,
        a_3_4,
        a_3_5
        sage: H.nil_preimage(4)
        a_1_0,
        a_1_1,
        b_2_1-b_2_0,
        b_2_2,
        b_2_3-b_2_0,
        a_3_4,
        a_3_5
        sage: H.nil_preimage(5)
        a_1_0,
        a_1_1,
        b_2_1+b_2_0,
        b_2_2+b_2_0,
        b_2_3+b_2_0,
        a_3_4,
        a_3_5

    A cohomology class is nilpotent if and only if its restriction to all maximal elementary abelian subgroups is nilpotent. Hence, the nil radical of `H` is the intersection of the above ideals, namely:

        sage: H.nil_preimage(2).intersect(H.nil_preimage(3)).intersect(H.nil_preimage(4)).intersect(H.nil_preimage(5)).groebner()
        a_1_0,
        a_1_1,
        a_3_4,
        a_3_5

  `nil_radical`()

    Permanently cached method: Compute the nil radical of `self`.

    OUTPUT:

    An ideal (Groebner basis) defined in the singular interface, representing the ideal of nilpotent elements of self.

    THEORY:

    An element of a cohomology ring is nilpotent if and only if its restriction to all maximal elementary abelian subgroups is nilpotent. Hence, we compute the intersection of the preimages of the nil radicals of the cohomology rings of the maximal elementary abelian subgroups. The ideal belongs to `singular(self)`.

    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: N = H.nil_radical()
        sage: singular(H).set_ring()
        sage: N
        a_1_0,
        a_1_1,
        a_3_4,
        a_3_5

    It is not always the case that the nil radical is generated by nilpotent generators. Here is an example of order 64, that is part of the data base in this package. We verify that the generators of the nil radical are indeed non-zero and nilpotent:

        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: print(H('b_1_0*b_1_2+b_1_0^2'))
        2-Cocycle in H^*(Syl2(L3(4)); GF(2)),
        represented by
        [1 0 1 0 0 0 0 0]
        sage: print(H('b_1_0*b_1_3+b_1_0*b_1_1+b_1_0^2'))
        2-Cocycle in H^*(Syl2(L3(4)); GF(2)),
        represented by
        [1 1 0 1 0 0 0 0]
        sage: print(H('b_1_0*b_1_2+b_1_0^2')^2)
        4-Cocycle in H^*(Syl2(L3(4)); GF(2)),
        represented by
        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]
        sage: print(H('b_1_0*b_1_3+b_1_0*b_1_1+b_1_0^2')^2)
        4-Cocycle in H^*(Syl2(L3(4)); GF(2)),
        represented by
        [0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0]

    In a previous version, the nil radical of the cohomology ring of an abelian group was incorrectly computed. Let us test that it is fixed:

        sage: H = CohomologyRing(16,2)
        sage: H.make()
        sage: H.nil_radical()
        c_1_0,
        c_1_1
        sage: print(H)
        <BLANKLINE>
        Cohomology ring of Small Group number 2 of order 16 with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [c_2_1: 2-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_2_2: 2-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_1_0: 1-Cocycle in H^*(SmallGroup(16,2); GF(2)),
         c_1_1: 1-Cocycle in H^*(SmallGroup(16,2); GF(2))]
        Minimal list of algebraic relations:
        [c_1_0^2,
         c_1_1^2]

  `nilspace`(d)

    Return a basis of the space of nilpotent elements in degree \(d\).

    INPUT:

    - \(d\), the degree (integer)

    OUTPUT:

    - A list of elements of `self` forming a basis of the degree \(d\) nilpotent elements.

    NOTE:

    The method `nil_radical()` returns the ideal formed by all nilpotent elements, which probably is more useful in practical applications. However, it may happen that the nil radical can not easily be computed, and then it may be helpful to compute it degree by degree.

    Warning

    This method is only implemented in characteristic 2!

    ALGORITHM:

    An element of a mod-\(2\) cohomology ring of a finite group \(G\) is nilpotent if and only if the restrictions to all maximal \(2\)-elementary abelian subgroups of \(G\) is zero.

    See also

    `nil_radical()`

    EXAMPLES:

    The following three cohomology rings have the same generator degrees and Poincaré series:

        sage: from pGroupCohomology import CohomologyRing
        sage: H1 = CohomologyRing(64, 18)
        sage: H2 = CohomologyRing(64, 19)
        sage: H3 = CohomologyRing(64, 25)
        sage: H1.poincare_series() == H2.poincare_series() == H3.poincare_series()
        True
        sage: H1.degvec == H2.degvec == H3.degvec
        True

    However, the cohomology rings are not isomorphic, which is shown by the Poincaré series of their nil radicals. We compute the difference with the Poincaré series of the cohomology ring, since this tells the dimension of the nil radical in each degree:

        sage: p1 = H1.poincare_series() - H1._poincare_series_of_ideal_(H1.nil_radical())
        sage: p2 = H2.poincare_series() - H2._poincare_series_of_ideal_(H2.nil_radical())
        sage: p3 = H3.poincare_series() - H3._poincare_series_of_ideal_(H3.nil_radical())
        sage: p1!=p2!=p3!=p1
        True
        sage: P.<t> = PowerSeriesRing(QQ)
        sage: P(p1.numerator())/p1.denominator()
        2*t + 2*t^2 + 4*t^3 + 4*t^4 + 6*t^5 + 8*t^6 + 9*t^7 + 10*t^8 + 13*t^9 + 14*t^10 + 17*t^11 + 18*t^12 + 21*t^13 + 24*t^14 + 26*t^15 + 28*t^16 + 32*t^17 + 34*t^18 + 38*t^19 + 40*t^20 + O(t^21)
        sage: P(p2.numerator())/p2.denominator()
        2*t + 2*t^2 + 4*t^3 + 4*t^4 + 4*t^5 + 6*t^6 + 7*t^7 + 8*t^8 + 11*t^9 + 12*t^10 + 15*t^11 + 16*t^12 + 17*t^13 + 20*t^14 + 22*t^15 + 24*t^16 + 28*t^17 + 30*t^18 + 34*t^19 + 36*t^20 + O(t^21)
        sage: P(p3.numerator())/p3.denominator()
        2*t + 2*t^2 + 4*t^3 + 4*t^4 + 5*t^5 + 7*t^6 + 8*t^7 + 9*t^8 + 12*t^9 + 13*t^10 + 16*t^11 + 17*t^12 + 19*t^13 + 22*t^14 + 24*t^15 + 26*t^16 + 30*t^17 + 32*t^18 + 36*t^19 + 38*t^20 + O(t^21)

    Hence, we expect to see different dimensions of the nil radical starting in degree 5. Let is compare with the results of a degree-wise computation:

        sage: [len(H1.nilspace(d)) for d in range(10)]
        [0, 2, 2, 4, 4, 6, 8, 9, 10, 13]
        sage: [len(H2.nilspace(d)) for d in range(10)]
        [0, 2, 2, 4, 4, 4, 6, 7, 8, 11]
        sage: [len(H3.nilspace(d)) for d in range(10)]
        [0, 2, 2, 4, 4, 5, 7, 8, 9, 12]

    Here are explicit bases in degree 5:

        sage: H1.nilspace(5)
        [a_5_8: 5-Cocycle in H^*(SmallGroup(64,18); GF(2)),
         a_5_5: 5-Cocycle in H^*(SmallGroup(64,18); GF(2)),
         ((b_2_3)**2)*(a_1_1): 5-Cocycle in H^*(SmallGroup(64,18); GF(2)),
         ((b_2_2)**2)*(a_1_0): 5-Cocycle in H^*(SmallGroup(64,18); GF(2)),
         (a_2_0)*(b_3_5): 5-Cocycle in H^*(SmallGroup(64,18); GF(2)),
         (a_2_0)*(b_3_4): 5-Cocycle in H^*(SmallGroup(64,18); GF(2))]
        sage: H2.nilspace(5)
        [((b_2_2)**2)*(a_1_1): 5-Cocycle in H^*(SmallGroup(64,19); GF(2)),
         (a_2_1)*(b_3_5): 5-Cocycle in H^*(SmallGroup(64,19); GF(2)),
         (a_2_0)*(b_3_5): 5-Cocycle in H^*(SmallGroup(64,19); GF(2)),
         (a_2_0)*(b_3_4): 5-Cocycle in H^*(SmallGroup(64,19); GF(2))]
        sage: H3.nilspace(5)
        [a_5_4: 5-Cocycle in H^*(SmallGroup(64,25); GF(2)),
         ((b_2_2)**2)*(a_1_1): 5-Cocycle in H^*(SmallGroup(64,25); GF(2)),
         ((b_2_2)**2)*(a_1_0): 5-Cocycle in H^*(SmallGroup(64,25); GF(2)),
         (a_2_1)*(b_3_5): 5-Cocycle in H^*(SmallGroup(64,25); GF(2)),
         (a_2_0)*(b_3_5): 5-Cocycle in H^*(SmallGroup(64,25); GF(2))]

  `nrels`()

    Return the minimal number of relations of `self`.

    NOTE:

    The list of relations may change if an incomplete cohomology computation is continued.

    For \(p>2\), any generator \(x\) of odd degree of the modular cohomology ring of a finite \(p\)-group gives rise to the relation \(x^2=0\). We refer to such relation as obvious. In the current version of our package, we count only the non-obvious relations, but this might change in future versions.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,3, from_scratch=True)
        sage: H.make(2)
        sage: H.nrels()
        2
        sage: H.make()
        sage: H.nrels()
        4
        sage: len(H.rels())
        4

  `order_matrix`()

    Temporarily cached method: Return an integer matrix that defines the term order of `self`.

    Even if the order is \(dp\), a matrix is returned.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(32,6, from_scratch=True)
        sage: H.make(2)
        sage: H.order_matrix()
        [ 2  2  2  1  1]
        [ 0  0  0 -1  0]
        [-1  0  0  0  0]
        [ 0 -1  0  0  0]
        [ 0  0 -1  0  0]
        sage: H.make()
        sage: H.order_matrix()
        [ 2  2  2  4  1  1  3  3]
        [ 0  0  0 -1  0  0  0  0]
        [ 0  0  0  0 -1  0  0  0]
        [-1  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]
        [ 0  0  0  0  0  0 -1  0]
        sage: tmp = tmp_dir()
        sage: CohomologyRing.set_workspace(tmp)
        sage: H = CohomologyRing(32,6, from_scratch=True)
        sage: H.setprop('use_dp',True)
        sage: H.make(2)
        sage: H.order_matrix()
        [ 2  2  2  1  1]
        [ 0  0  0  0 -1]
        [ 0  0  0 -1  0]
        [ 0  0 -1  0  0]
        [ 0 -1  0  0  0]
        sage: H.make()
        sage: H.order_matrix()
        [ 2  2  2  4  1  1  3  3]
        [ 0  0  0  0  0  0  0 -1]
        [ 0  0  0  0  0  0 -1  0]
        [ 0  0  0  0  0 -1  0  0]
        [ 0  0  0  0 -1  0  0  0]
        [ 0  0  0 -1  0  0  0  0]
        [ 0  0 -1  0  0  0  0  0]
        [ 0 -1  0  0  0  0  0  0]

  `parameters`(**kwds)

    Permanently cached method: Return small parameters that are algebraically independent.

    OUTPUT:

    `None`, if the ring approximation does not contain parameters for the cohomology ring. Otherwise, a sequence of elements, forming a hsop of the cohomology ring, but not necessarily of the ring approximation.

    THEORY:

    We start with a filter-regular hsop, as provided by `filter_regular_parameters()`. Then, we try to replace any of these parameters by a parameter of smaller degree. The result is not guaranteed to be filter regular, of course.

    NOTE:

    Compared with previous versions of this spkg, the heuristics to find parameters in smaller degrees has substantially improved in version 2.1.4.

    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', from_scratch=True)
        sage: H.make(7)

    In this example, it was not automatically attempted to lift Dickson elements. Since the Dickson elements are the starting point of parameter construction in this case, we do not find parameters, even though they do exist:

        sage: H.parameters()
        sage: H.verify_parameters_exist()
        True

    We now use elimination to find paramters:

        sage: H.find_dickson()
        True

    The result of `parameters()` is cached as long as the ring structure doesn’t change. Here, the ring structure has changed since the previous call to the method, and indeed we can now find parameters:

        sage: H.parameters()
        ['b_2_0^2+c_4_1',
         'b_3_1^4+b_3_0^4+b_6_2*b_3_1^2+b_6_2^2+b_2_0^3*b_6_2+c_4_1*b_3_1*b_5_2+b_2_0*c_4_1*b_3_1^2+b_2_0^2*c_4_1^2',
         'b_7_6+c_4_1*b_3_1+c_4_1*b_3_0',
         'b_6_2']

    These elements are guaranteed to form a homogeneous system of parameters of the cohomology ring, but they are not parameters of the current ring approximation:

        sage: I = H.relation_ideal()
        sage: singular.eval('degBound = 0')
        ''
        sage: print(singular.eval('dim(groebner(%s+ideal(%s)))'%(I.name(), ','.join(H.parameters()))))
        4

    Continuing to degree 14, thus, having more relations, the above parameters do indeed turn into parameters for the ring approximation:

        sage: H.make(14)
        sage: I = H.relation_ideal()
        sage: print(singular.eval('dim(groebner(%s+ideal(%s)))'%(I.name(), ','.join(H.parameters()))))
        0

  `poincare_series`(test_duality=False)

    Temporarily cached method: Return the Poincaré series of `self`, a univariate rational function.

    ALGORITHM:

    If Benson’s criterion was used to proof completeness of the ring structure, it was needed to verify that certain parameters of the ring are filter regular. This involves computing kernel and quotients of multiplication maps. These data are saved, and now used for the computation of the Poincaré series.

    Otherwise, some standard way of computation from commutative algebra is used.

    INPUT:

    `test_duality` – (bool, default `False`) If this argument is `True` and``self`` is already completed and happens to be Cohen-Macaulay, a self consistence check is applied, based on Benson-Carlson duality [BensonCarlson].

    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.poincare_series()
        1/(t^2 - 2*t + 1)

  `potential_degree_bound`(FRS, dv, forced=1, previous_bound=None)

    Return the potential degree bound obtained from the modified Benson test.

    INPUT:

    - `FRS`: a list of polynomials (given by strings)

    - `DV`: the list of degrees of the polynomials from `FRS`

    - `forced` (optional int); let \(n\) be the degree up to which the cohomology is known

      - If `forced == 2`: return the best possible bound, even if it is smaller than \(n\)

      - If `forced == 1`: the best potential bound, if it is greater than \(n\), or some potential bound if it is at most \(n\).

    ASSUMPTION:

    `FRS` were a filter regular HSOP, provided self was completely computed.

    THEORY:

    See [GreenKing], Proposition 3.2 and Theorem 3.3.

    EXAMPLES:

    We first create a cohomology ring. For constructing Dickson classes, we use the linear algebra method.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(27,3, useElimination=False, from_scratch=True)

    The computational steps in this example will internally be done by `H.make()`. Here, we do them step by step.

        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.next()
        sage: H.gens()
        [1,
         b_2_0: 2-Cocycle in H^*(E27; GF(3)),
         b_2_1: 2-Cocycle in H^*(E27; GF(3)),
         b_2_2: 2-Cocycle in H^*(E27; GF(3)),
         b_2_3: 2-Cocycle in H^*(E27; GF(3)),
         c_6_8: 6-Cocycle in H^*(E27; GF(3)),
         a_1_0: 1-Cocycle in H^*(E27; GF(3)),
         a_1_1: 1-Cocycle in H^*(E27; GF(3)),
         a_3_4: 3-Cocycle in H^*(E27; GF(3)),
         a_3_5: 3-Cocycle in H^*(E27; GF(3))]

    During these computations, Dickson classes have been computed. We found:

        sage: H.Dickson
        ['b_2_3^2-b_2_0*b_2_2-b_2_0*b_2_1+b_2_0^2']

    It is known that the Duflot regular generator `c_6_8` and the Dickson class form a filter regular homogeneous HSOP of `H`, provided the computation is complete. However, Benson’s criterion would only apply in degree 5+3+1=9. Now we test whether it is possible to replace the Dickson class by a parameter of smaller degree over some finite extension field. If there is more than one Dickson class, we would potentially replace several (but not necessarily all) of them. Note that our method is not constructive – we just show the existence of a filter regular HSOP! In general, it is inevitable to extend the coefficient field.

        sage: H.potential_degree_bound(['c_6_8','b_2_3^2-b_2_0*b_2_2-b_2_0*b_2_1+b_2_0^2'],[6,4])
        7

    The previous line means: If `['c_6_8','b_2_3^2-b_2_0*b_2_2-b_2_0*b_2_1+b_2_0^2']` gives rise to a filter regular HSOP of a ring approximation out to degree at least seven, and if the \(n\)-th term of the resulting filter degree type is not greater than \(-n\) for all but the last term, then the ring approximation is complete. Indeed:

        sage: H.raw_filter_degree_type(['c_6_8','b_2_3^2-b_2_0*b_2_2-b_2_0*b_2_1+b_2_0^2'])
        ([-1, -1, 8], [[0], [0], [1, 2, 4, 6, 6, 6, 4, 2, 1]], [6, 4])
        sage: H.filter_degree_type()
        [-1, -2, -2]

    So, we have shown that the cohomology computation is complete.

  `printed_group_name`()

    Group identifier used for printing.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.reset()
        sage: CohomologyRing(8,3).printed_group_name()
        'D8'
        sage: CohomologyRing(64,167).printed_group_name()
        'SmallGroup(64,167)'

  `properties`()

    List the names of the custom attributes set with `setprop()`.

    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: sorted(H.properties())
        ['DicksonExp',
         'GroupDescr',
         'GroupName',
         'KeepBases',
         '_key',
         'auto',
         'root',
         'sgpDickson',
         'useElimination',
         'useFactorization']

    During the computation, more properties are added:

        sage: H.make()
        sage: sorted(H.properties())
        ['DicksonExp',
         'GroupDescr',
         'GroupName',
         'KeepBases',
         '_SymondsTestdata',
         '_key',
         '_max_module_deg',
         '_method',
         '_parameters_for_criterion',
         'auto',
         'completeGroebner',
         'root',
         'sgpDickson',
         'useElimination',
         'useFactorization']

  `raw_filter_degree_type`(FRS)

    Temporarily cached method: Test whether a given list of elements forms a filter-regular HSOP.

    INPUT:

    - `FRS`: a list of strings defining elements of the cohomology ring

    OUTPUT:

    - `None`, if the input is not a filter regular HSOP.

    - Otherwise, a triple of lists of numbers is returned:

      - The “raw filter degree type” of that HSOP

      - Data that are of internal use to compute the Poincaré series

      - The degree vector of the parameters.

    EXAMPLES:

    We first create a cohomology ring. For constructing Dickson classes, we use the elimination method.

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

    Of course, Dickson classes are not there, yet, so we construct them.

        sage: H.Dickson
        [None]
        sage: H.find_dickson()
        True
        sage: H.Dickson
        ['b_1_1+b_1_0']

    There is one Duflot regular class:

        sage: [X for X in H.Gen if X.rdeg()]
        [c_2_2: 2-Cocycle in H^*(D8; GF(2))]

    So, if the computation was complete, `c_2_2` and `b_1_1+b_1_0` were a filter regular HSOP in degrees 2 and 1. This is indeed the case, as we verify now:

        sage: H.raw_filter_degree_type(['c_2_2','b_1_1+b_1_0'])
        ([-1, -1, 1], [[0], [0], [1, 1]], [2, 1])

    The raw filter degree type is the first item in the above triple. The filter degree type of that HSOP is now available:

        sage: H.filter_degree_type()
        [-1, -2, -2]

    Now, we try a slightly different sequence of elements:

        sage: H.raw_filter_degree_type(['c_2_2^2','b_1_0^2+b_1_1^2'])
        ([-1, -1, 4], [[0], [0], [1, 2, 2, 2, 1]], [4, 2])

    It is known that the filter degree type is the same for any filter regular HSOP. But apparently the raw filter degree type is different.

  `reconstructSubgroups`()

    When loading a cohomology ring, the subgroups are not reconstructed immediately. This is done here.

    NOTE:

    It is not necessary to call this function manually. It is done automaticall as soon as the subgroups are requested.

    EXAMPLES:

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

    In this example, we do not want that the cohomology rings are cached. Hence, we destroy cache:

        sage: CohomologyRing._cache.clear()
        sage: K = loads(dumps(H))
        sage: K is H
        False

    The point is that `subgps` is an attribute that is not immediately created when a cohomology ring is loaded. So, although `H` has this attribute, `K` hasn’t:

        sage: 'subgps' in H.__dict__
        True
        sage: 'subgps' in K.__dict__
        False

    It is created using this method:

        sage: K.reconstructSubgroups()
        sage: 'subgps' in K.__dict__
        True

    The method is automatically called when trying to access the `subgps` attribute:

        sage: for k,v in list(CohomologyRing._cache.items()):
        ....:     if v is K:
        ....:         del CohomologyRing._cache[k]
        sage: L = loads(dumps(K))
        sage: 'subgps' in L.__dict__
        False
        sage: CohomologyRing.global_options('info')
        sage: sorted(L.subgps.items())
        H^*(D8; GF(2)):
            Inserting SmallGroup(4,2) as a subgroup
            Inserting SmallGroup(2,1) as a subgroup
            Reconstructing subgroup data
        [((2, 1), H^*(SmallGroup(2,1); GF(2))), ((4, 2), H^*(SmallGroup(4,2); GF(2)))]

  `reconstruct_singular`()

    Reconstruct data after the Singular interface crashed.

    NOTE:

    We tried to make this method robust emough that computations involving Singular can be interrupted at any point.

    EXAMPLES:

    We start a cohomology computation and carry it out to degree 3.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(720,763,prime=2, from_scratch=True)
        sage: H.make(3)

    We now simulate a crash of Singular. After reconstructing the data, the computation can proceed as usual. By logging, we show what happens internally.

        sage: singular.quit()
        sage: CohomologyRing.global_options('info')
        sage: H.reconstruct_singular()
        H^*(SmallGroup(720,763); GF(2)):
            Reconstructing data in the Singular interface
        H^*(D8xC2; GF(2)):
            Reconstructing data in the Singular interface
        H^*(SmallGroup(8,5); GF(2)):
            Reconstructing data in the Singular interface
        H^*(SmallGroup(4,2); GF(2)):
            Reconstructing data in the Singular interface

    Even after the simulated crash, we can continue with the computation:

        sage: CohomologyRing.global_options('warn')
        sage: H.make(7)
        sage: H.find_dickson()
        True
        sage: H.parameters()
        ['c_1_0', 'c_2_1', 'b_3_3+c_3_2']
        sage: H.make()
        sage: print(H)
        Cohomology ring of SmallGroup(720,763) with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [c_2_1: 2-Cocycle in H^*(SmallGroup(720,763); GF(2)),
         c_1_0: 1-Cocycle in H^*(SmallGroup(720,763); GF(2)),
         b_3_3: 3-Cocycle in H^*(SmallGroup(720,763); GF(2)),
         c_3_2: 3-Cocycle in H^*(SmallGroup(720,763); GF(2))]
        Minimal list of algebraic relations:
        [b_3_3*c_3_2+c_2_1*c_1_0*b_3_3]

    Note that this method is automatically called when Singular is called on the cohomology ring:

        sage: CohomologyRing.global_options('info')
        sage: singular(H)
        polynomial ring, over a field, global ordering
        // coefficients: ZZ/2
        // number of vars : 4
        //        block   1 : ordering M
        //                  : names    c_2_1 c_1_0 b_3_3 c_3_2
        //                  : weights      2     1     3     3
        //                  : weights     -1    -1     0    -1
        //                  : weights     -1     0     0     0
        //                  : weights      0    -1     0     0
        //        block   2 : ordering C
        // quotient ring from ideal
        _[1]=b_3_3*c_3_2+c_2_1*c_1_0*b_3_3
        sage: singular.quit()
        sage: singular(H)
        H^*(SmallGroup(720,763); GF(2)):
            Reconstructing data in the Singular interface
        H^*(D8xC2; GF(2)):
            Reconstructing data in the Singular interface
        H^*(SmallGroup(8,5); GF(2)):
            Reconstructing data in the Singular interface
        H^*(SmallGroup(4,2); GF(2)):
            Reconstructing data in the Singular interface
        polynomial ring, over a field, global ordering
        // coefficients: ZZ/2
        // number of vars : 4
        //        block   1 : ordering M
        //                  : names    c_2_1 c_1_0 b_3_3 c_3_2
        //                  : weights      2     1     3     3
        //                  : weights     -1    -1     0    -1
        //                  : weights     -1     0     0     0
        //                  : weights      0    -1     0     0
        //        block   2 : ordering C
        // quotient ring from ideal
        _[1]=b_3_3*c_3_2+c_2_1*c_1_0*b_3_3

    TESTS:

    The following used to fail in at some point in the development of this package.

        sage: CohomologyRing.doctest_setup()        # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(48,50, prime=2)
        sage: H.make()
        sage: c = H.subgroup_cohomology()('c_1_1*c_1_2^2*c_1_3^3+c_1_1*c_1_2^4*c_1_3+c_1_1*c_1_2^5+c_1_1^2*c_1_3^4+c_1_1^2*c_1_2*c_1_3^3+c_1_1^2*c_1_2^3*c_1_3+c_1_1^3*c_1_2^2*c_1_3+c_1_1^3*c_1_2^3+c_1_1^4*c_1_3^2+c_1_1^4*c_1_2*c_1_3+c_1_1^4*c_1_2^2+c_1_1^5*c_1_2+c_1_0*c_1_3^5+c_1_0*c_1_2^2*c_1_3^3+c_1_0*c_1_2^3*c_1_3^2+c_1_0*c_1_1^2*c_1_2*c_1_3^2+c_1_0*c_1_1^2*c_1_2^2*c_1_3+c_1_0*c_1_1^2*c_1_2^3+c_1_0*c_1_1^3*c_1_3^2+c_1_0*c_1_1^3*c_1_2^2+c_1_0*c_1_1^4*c_1_3+c_1_0*c_1_1^5+c_1_0^2*c_1_3^4+c_1_0^2*c_1_2^2*c_1_3^2+c_1_0^2*c_1_2^3*c_1_3+c_1_0^2*c_1_2^4+c_1_0^2*c_1_1*c_1_3^3+c_1_0^2*c_1_1*c_1_2^2*c_1_3+c_1_0^2*c_1_1^2*c_1_2*c_1_3+c_1_0^2*c_1_1^2*c_1_2^2+c_1_0^2*c_1_1^3*c_1_2+c_1_0^3*c_1_2*c_1_3^2+c_1_0^3*c_1_1*c_1_2^2+c_1_0^3*c_1_1^2*c_1_3+c_1_0^3*c_1_1^3+c_1_0^4*c_1_3^2+c_1_0^4*c_1_2*c_1_3+c_1_0^4*c_1_2^2+c_1_0^4*c_1_1*c_1_2+c_1_0^4*c_1_1^2+c_1_0^5*c_1_3+c_1_0^5*c_1_1')
        sage: d = H.stable_to_polynomial(c); d
        c_3_6^2+c_3_2*c_3_7+c_3_2*c_3_6+c_3_0*c_3_7+c_3_0*c_3_6+c_3_0*c_3_5+c_3_0*c_3_4+c_3_0*c_3_3+c_2_3^3+c_2_2*c_2_3^2+c_2_1^2*c_2_3+c_2_1^3+c_2_0*c_2_3^2+c_2_0*c_2_1*c_2_2+c_2_0*c_2_1^2+c_2_0^2*c_2_3: 6-Cocycle in H^*(SmallGroup(48,50); GF(2))
        sage: R = H.find_relations(6)
        sage: [r.name() for r in R[0]]
        ['c_3_6*c_3_7+c_3_6^2+c_2_3^3', 'c_3_6^2+c_2_3^3',
         'c_3_4*c_3_7+c_3_4*c_3_6+c_2_1*c_2_3^2', 'c_3_4*c_3_7',
         'c_3_2*c_3_6+c_2_1^2*c_2_3', 'c_3_2*c_3_7',
         'c_3_0*c_3_7+c_3_0*c_3_6+c_2_1^2*c_2_2+c_2_1^3+c_2_0*c_2_2*c_2_3',
         'c_3_0*c_3_7', 'c_3_6^2', 'c_3_4*c_3_7+c_2_2*c_2_3^2',
         'c_3_4*c_3_6', 'c_3_2*c_3_6+c_2_1*c_2_2*c_2_3+c_2_0*c_2_3^2',
         'c_3_2*c_3_7+c_3_2*c_3_6+c_2_1*c_2_2*c_2_3+c_2_1^2*c_2_3',
         'c_3_2*c_3_7+c_2_1^2*c_2_3', 'c_2_1^3+c_2_0*c_2_2*c_2_3+c_2_0*c_2_1*c_2_3',
         'c_2_1^2*c_2_2+c_2_1^3+c_2_0*c_2_1*c_2_3', 'c_3_0*c_3_7+c_2_1^2*c_2_2',
         'c_3_0*c_3_6+c_2_1^2*c_2_2+c_2_0*c_2_2*c_2_3',
         'c_3_0*c_3_5+c_3_0*c_3_4+c_2_0*c_2_1^2', 'c_3_0*c_3_5+c_2_0*c_2_1^2+c_2_0^2*c_2_3',
         'c_3_0*c_3_4+c_2_0*c_2_1*c_2_2+c_2_0*c_2_1^2', 'c_3_0*c_3_5+c_3_0*c_3_4+c_2_0^2*c_2_3',
         'c_3_0*c_3_5+c_2_0*c_2_1*c_2_2+c_2_0^2*c_2_3', 'c_3_0*c_3_2+c_2_0^2*c_2_1',
         'c_3_0*c_3_3', 'c_3_0*c_3_2+c_2_0^2*c_2_2+c_2_0^2*c_2_1', 'c_3_0*c_3_3+c_2_0^2*c_2_1',
         'c_3_0*c_3_1+c_3_0^2+c_2_0^3', 'c_3_0^2+c_2_0^3', 'c_3_0^2']
        sage: singular.quit()
        sage: d == H.stable_to_polynomial(c) #indirect doc test
        H^*(SmallGroup(16,14); GF(2)):
            Reconstructing data in the Singular interface
        H^*(SmallGroup(48,50); GF(2)):
            Reconstructing data in the Singular interface
        True
        sage: R == H.find_relations(6)
        True

  `rel`(i)

    Return a relation of `self`, represented by a string.

    NOTE:

    For \(p>2\), any generator \(x\) of odd degree of the modular cohomology ring of a finite \(p\)-group gives rise to the relation \(x^2=0\). We refer to such relation as obvious. In the current version of our package, we list only the non-obvious relations, but this might change in future versions.

    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: H.rels()
        ['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.rel(0)
        'a_1_0^2'
        sage: H.rel(2)
        'b_2_1*a_1_0'

  `relation_ideal`()

    Return the relation ideal for the current ring approximation.

    OUTPUT:

    An ideal in the Singular interface. It is a Groebner basis at least out to the known degree of the ring approximation.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(192,1493,prime=2, from_scratch=True)
        sage: H.make(4)
        sage: H.set_ring()
        sage: H.relation_ideal()
        b_1_0*b_3_0+b_2_1^2+b_2_0*b_2_2,
        b_1_0*b_3_2,
        b_1_0*b_3_5,
        b_1_0*b_3_6
        sage: H.make()
        sage: H.set_ring()
        sage: H.relation_ideal()
        b_1_0*b_3_0+b_2_1^2+b_2_0*b_2_2,
        b_1_0*b_3_2,
        b_1_0*b_3_5,
        b_1_0*b_3_6,
        b_2_0*b_3_6+b_2_0*b_3_5,
        b_2_1*b_3_2+b_2_0*b_3_5,
        b_2_1*b_3_5+b_2_0*b_3_5,
        b_2_1*b_3_6+b_2_0*b_3_5,
        b_2_2*b_3_2+b_2_0*b_3_5,
        b_2_2*b_3_5+b_2_0*b_3_5,
        b_3_0^2+b_2_1^2*b_2_2+b_2_1^3+b_2_0*b_2_1*b_2_2+b_2_0*b_2_1^2+c_4_10*b_1_0^2,
        b_3_0*b_3_2,
        b_3_0*b_3_5,
        b_3_0*b_3_6,
        b_3_2*b_3_6+b_3_2*b_3_5,
        b_3_5^2+b_3_2*b_3_5,
        b_3_5*b_3_6+b_3_2*b_3_5,
        b_2_1^2*b_3_0+b_2_1^2*b_2_2*b_1_0+b_2_1^3*b_1_0+b_2_0*b_2_2*b_3_0+b_2_0*b_2_1*b_2_2*b_1_0+b_2_0*b_2_1^2*b_1_0+c_4_10*b_1_0^3,
        b_2_1^2*b_2_2*b_1_0^2+b_2_1^3*b_1_0^2+b_2_1^4+b_2_0*b_2_1*b_2_2*b_1_0^2+b_2_0*b_2_1^2*b_1_0^2+b_2_0^2*b_2_2^2+c_4_10*b_1_0^4

  `rels`()

    Return the list of minimal relations of `self`, represented by strings.

    NOTE:

    The list of relations may change if an incomplete cohomology computation is continued.

    For \(p>2\), any generator \(x\) of odd degree of the modular cohomology ring of a finite \(p\)-group gives rise to the relation \(x^2=0\). We refer to such relation as obvious. In the current version of our package, we list only the non-obvious relations, but this might change in future versions.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,3, from_scratch=True)
        sage: H.make(2)
        sage: H.rels()
        ['a_1_0^2', 'a_1_0*b_1_1']
        sage: H.make()
        sage: H.rels()
        ['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']

  `resolution`()

    Return the underlying resolution of `self`.

    Of course, when computing the cohomology ring in increasing degree, more and more terms of the resolution will be computed.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,5, from_scratch=True)
        sage: H
        H^*(SmallGroup(16,5); GF(2))
        sage: print(H.resolution())
        Resolution:
        0 <- GF(2) <- GF(2)[SmallGroup(16,5)]
        sage: H.make()
        sage: print(H.resolution())
        Resolution:
        0 <- GF(2) <- GF(2)[SmallGroup(16,5)] <- rank 2 <- rank 3 <- rank 4

  `restrict_to_subgroup`(n)

    Returns the restriction of the cohomology ring generators to the \(n\)-th subgroup.

    SEE ALSO:

    - `restrictions_as_string()`

    INPUT:

    - `n`: an integer indicating a special subgroup

      - `n=1` refers to the greatest central elementary abelian subgroup

      - `n>1` refers to a representative of conjugacy classes of maximal elementary abelian subgroups

    OUTPUT:

    A list of cochains of the specified subgroup, obtained by restricting the generators 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()

    H has two isomorphism types of special subgroups, but 3 conjugacy classes:

        sage: len(H.subgroups())
        2
        sage: len(H.restriction_maps())
        3

    We show the restriction to the three conjugacy classes. First, the greatest central elementary abelian subgroup:

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

    Now the restrictions to the maximal elementary abelian subgroups:

        sage: H.restrict_to_subgroup(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))]
        sage: H.restrict_to_subgroup(3)
        [c_1_0*c_1_1+c_1_0^2: 2-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         0: 1-Cocycle in H^*(SmallGroup(4,2); GF(2)),
         c_1_1: 1-Cocycle in H^*(SmallGroup(4,2); GF(2))]

  `restriction_maps`()

    Return the dictionary of restriction maps of `self`.

    OUTPUT:

    A dictionary of induced homomorphisms, namely the restriction maps of self to conjugacy classes of maximal elementary abelian subgroups or to the greatest central elementary abelian subgroup. The greatest central elementary abelian subgroup is available with the index `1`.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,3)
        sage: sorted(H.restriction_maps().items())
        [(1,
          [(4, 2),
           Induced homomorphism of degree 0 from H^*(SmallGroup(16,3); GF(2)) to H^*(SmallGroup(4,2); GF(2))]),
         (2,
          [(8, 5),
           Induced homomorphism of degree 0 from H^*(SmallGroup(16,3); GF(2)) to H^*(SmallGroup(8,5); GF(2))])]

  `restrictions_as_string`(n)

    Restriction of the cohomology ring generators to the \(n\)-th subgroup as list of strings.

    SEE ALSO:

    - `restrict_to_subgroup()`

    INPUT:

    - `n`: an integer indicating a special subgroup

      - `n=1` refers to the greatest central elementary abelian subgroup

      - `n>1` refers to a representative of conjugacy classes of maximal elementary abelian subgroups

    OUTPUT:

    A list of strings, representing a polynomial in the generators of the cohomology of the specified subgroup, yielding the restriction of the generators of self to that subgroup

    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()

    `H` has two isomorphism types of special subgroups, but 3 conjugacy classes:

        sage: len(H.subgroups())
        2
        sage: len(H.restriction_maps())
        3

    We show the restriction to the three conjugacy classes. First, the greatest central elementary abelian subgroup:

        sage: H.restrictions_as_string(1)
        ['c_1_0^2', '0', '0']

    Now the restrictions to the maximal elementary abelian subgroups:

        sage: H.restrictions_as_string(2)
        ['c_1_0*c_1_1+c_1_0^2', 'c_1_1', '0']
        sage: H.restrictions_as_string(3)
        ['c_1_0*c_1_1+c_1_0^2', '0', 'c_1_1']

  `set_ring`()

    The underlying free graded commutative ring of `self` in the Singular interface becomes the base ring.

    NOTE:

    This ring is, in general, not isomorphic to the cohomology ring, since the non-obvious relations are disregarded; the ring will only have the obvious quadratic relations that are common to any graded commutative ring in the Singular interface.

    You can obtain a ring in the Singular interface isomorphic to a cohomology ring `H` by simply doing `singular(H)`.

    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.subgroups()[4,2].set_ring()
        sage: print(singular.eval('basering'))
        // coefficients: ZZ/2
        // number of vars : 2
        //        block   1 : ordering M
        //                  : names    c_1_0 c_1_1
        //                  : weights      1     1
        //                  : weights     -1     0
        //        block   2 : ordering C
        sage: H.set_ring()
        sage: print(singular.eval('basering'))
        // coefficients: ZZ/2
        // number of vars : 3
        //        block   1 : ordering M
        //                  : names    c_2_2 b_1_0 b_1_1
        //                  : weights      2     1     1
        //                  : weights     -1     0     0
        //                  : weights      0    -1     0
        //        block   2 : ordering C

  `setprop`(key, value)

    Define a property of `self`.

    INPUT:

    - `key`, a string

    - `value`, any object

    OUTPUT:

    `value` is now available as an attribute `key` 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: print(H.foobar)
        None
        sage: print(H._foobar)
        None
        sage: print(H.foobar_)
        None

    Note that if an attribute hasn’t been defined, `None` is returned. The only exceptions are undefined attributes that start and end with an underscore:

        sage: H._foobar_
        Traceback (most recent call last):
        ...
        AttributeError: 'COHO' object has no attribute '_foobar_'

    Now, we provide `_foobar_` with a meaning, and then it works:

        sage: H.setprop('_foobar_', 'It works!')
        sage: print(H._foobar_)
        It works!

  `small_factor`(C, enumerate=False)

    Determine a small factor of an element, modulo nilpotent generators.

    INPUT:

    - `C` – an element of `self` or a polynomial in the Singular interface. If it is an element of `self`, `C.name()` must express `C` as polynomial in the generators of `self`.

    - `enumerate` – (bool, default `False`) If `True`, the factorisation takes into account the relations in `self`, but may take a long time, as the factors are found by enumeration of elements in small degrees.

    NOTE:

    In order to express `C` as a polynomial in the generators of `self`, use `element_as_polynomial()`.

    OUTPUT:

    A string, providing a small non-scalar factor of `C`, allowing modification by multiples of nilpotent generators.

    NOTE:

    If the optional argument `enumerate` is `True`, then in each degree, at most 1000 candidates are tested; this default can be altered by assigning a value to `pGroupCohomology.resolution.coho_options['NrCandidates']`.

    NOTE:

    If the computation is interrupted with Ctrl-c, the computation is continued in the next degree.

    EXAMPLES:

    We first load a cohomology ring of order 64 from the local sources shipped with this package.

        sage: from pGroupCohomology import CohomologyRing
        sage: H = CohomologyRing(64,235)
        sage: H.gens()
        [1,
         c_4_13: 4-Cocycle in H^*(SmallGroup(64,235); GF(2)),
         c_4_14: 4-Cocycle in H^*(SmallGroup(64,235); GF(2)),
         a_1_1: 1-Cocycle in H^*(SmallGroup(64,235); GF(2)),
         a_1_0: 1-Cocycle in H^*(SmallGroup(64,235); GF(2)),
         b_1_2: 1-Cocycle in H^*(SmallGroup(64,235); GF(2)),
         b_1_3: 1-Cocycle in H^*(SmallGroup(64,235); GF(2)),
         b_3_10: 3-Cocycle in H^*(SmallGroup(64,235); GF(2))]

    We construct a cochain of degree 6. A factorisation with the default arguments does not yield a factor of smaller degree; only the obvious nilpotent summand is removed:

        sage: p = H('b_1_3^3*b_3_10+c_4_14*b_1_3^2+c_4_14*b_1_2^2+c_4_13*b_1_3^2+c_4_13*b_1_2^2+c_4_13*a_1_0*a_1_1')
        sage: H.small_factor(p)
        'b_1_3^3*b_3_10+c_4_14*b_1_3^2+c_4_14*b_1_2^2+c_4_13*b_1_3^2+c_4_13*b_1_2^2'

    However, a smaller factor can be found if, in addition to nilpotent generators, the relations are taken into account, by using an optional argument:

        sage: CohomologyRing.global_options('info')
        sage: H.small_factor(p, enumerate=True)
        H^*(SmallGroup(64,235); GF(2)):
            Factorising an element; it can be interrupted with Ctrl-c
            Exploring factors of an element by enumeration (can be interrupted with Ctrl-c)
            Determine degree 1 standard monomials
            > Start enumeration with 2 monomials
        'b_1_3+b_1_2'

    We verify that indeed the difference of `p` and some multiple of the returned factor is nilpotent of order exactly 3:

        sage: CohomologyRing.global_options('warn')
        sage: f1 = H('b_1_3+b_1_2')
        sage: f2 = H('(b_1_3*b_3_10+c_4_14+c_4_13)*(b_1_3+b_1_2)')
        sage: ((singular(f1)*singular(f2) - singular(p))^2).NF('std(0)')
        c_4_14*a_1_1*a_1_0*b_1_2^6+c_4_13*a_1_1*a_1_0*b_1_2^6
        sage: ((singular(f1)*singular(f2) - singular(p))^3).NF('std(0)')
        0

  `standardCochain`(n, i, rdeg=None, ydeg=None, name='c')

    Standard cochain of `self`.

    INPUT:

    - `n`: degree (integer) of a cochain

    - `i`: integer

    - `rdeg`, `ydeg`: (optional) integers or `None` (default `None`).

    - `name`: (optional) string used to give the cochain a name (default `'c'`)

    OUTPUT:

    A \(n\)-cochain represented by `[0,...,0,1,0,...0]` with 1 at position \(i\) (counting from zero) and name `'c_%d_%d'%(n,i)`. The letter `'c'` in the name can be changed with the optional parameter ‘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.standardCochain(3,2,rdeg=1,ydeg=0,name='X')
        sage: c
        X_3_2: 3-Cocycle in H^*(D8; GF(2))
        sage: print(c)
        3-Cocycle in H^*(D8; GF(2)),
        represented by
        [0 0 1 0]
        rdeg = 1
        ydeg = 0

  `standard_monomials`(n)

    Standard monomials of a prescribed degree.

    INPUT:

    \(n\): An integer, so that `self` is known at least out to degree \(n\).

    OUTPUT:

    A list of strings, providing the degree-\(n\) standard monomials, sorted in descending order.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,4, from_scratch=True)
        sage: H.make(2)
        sage: H.standard_monomials(2)
        ['a_1_0*a_1_1', 'a_1_0^2']
        sage: H.standard_monomials(3)
        Traceback (most recent call last):
        ...
        ValueError: The cohomology ring is not known out to degree 3
        sage: H.make()

    We now know the cohomology ring entirely, although the explicit computation only went out to degree 4. But since we know all of the ring, we can now get the degree-\(5\) standard monomials:

        sage: H.knownDeg
        4
        sage: H.standard_monomials(5)
        ['c_4_0*a_1_1', 'c_4_0*a_1_0']

  `subgroups`()

    Return the subgroup dictionary of `self`.

    OUTPUT:

    A dictionary of cohomology rings of elementary abelian groups that occur as maximal elementary abelian subgroups or as the greatest central elementary abelian subgroup of the group over which self is defined. The dictionary is indexed by addresses for the SmallGroups libarary.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(16,3)
        sage: sorted(H.subgroups().items())
        [((4, 2), H^*(SmallGroup(4,2); GF(2))), ((8, 5), H^*(SmallGroup(8,5); GF(2)))]

  `test_for_completion`(forced=False)

    Test whether the current ring approximation is complete.

    OUTPUT:

    `True` (complete), `False` (incomplete) or `None` (can’t be decided yet)

    THEORY:

    We choose between two criteria:

    - The [Benson] criterion modified by [GreenKing]: It relies on the construction of a filter regular hsop for the ring approximation that is guaranteed to correspond to a hsop in cohomology, and on the existence of a filter regular hsop in small degrees over a finite extension of the coefficient field.

    - The [Symonds] criterion: It relies on the construction of a hsop for the cohomology in small degrees, and the generator degree of the ring approximation as a module over these parameters. These parameters do not need to be algebraically independent.

    The advantage of the Benson criterion is that often there exist fairly small parameters over a finite extension field that can not be found in the original cohomology ring; hence it may apply much earlier than the Symonds test. Note that if the rank of the centre of a Sylow subgroup is at least two then the degree bound drops by one.

    The advantage of the Symonds test is that it does not rely on filter regularity. Often, one finds a general hsop in smaller degrees than a filter regular hsop. Moreover, it is not needed to compute the filter degree type of the ring, which can be a very difficult part of Benson’s test. Note that the rank of the centre of a Sylow subgroup has no influence on the degree bound.

    We give more details in the documentation of `pGroupCohomology`.

    ALGORITHM:

    - If the Symonds test has a chance to apply (which can be seen in the degrees of the hsop) then it is tried.

    - If the Symonds test has no chance to apply yet, Benson’s test is chosen.

    EXAMPLES:

    We compute the rings in a way that avoids the automatic execution of this method.

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H64 = CohomologyRing(64,6, useElimination=True, from_scratch=True)
        sage: H64.make(3)
        sage: H64.next()

    Now, the ring structure is known out to degree four. A hsop can be found in sufficiently small degrees. Therefore, the Symonds test is chosen, which can be seen in the log and in the attribute `_method`:

        sage: H64.parameters()
        ['c_2_2', 'c_2_3', 'b_1_1']
        sage: CohomologyRing.global_options('info')
        sage: H64.test_for_completion()
        H^*(SmallGroup(64,6); GF(2)):
            Compute dependent_parameters
            Try to find a set of generators over which the cohomology ring is finite.
            Trying Symonds' criterion
            Successful application of the Symonds criterion
        True
        sage: CohomologyRing.global_options('warn')
        sage: H64._method
        'Symonds'
        sage: H64.completed
        True

    In our second example, the Benson criterion is used. Again, we compute the ring structure to a sufficient degree, but avoiding the automatic completion testing.

        sage: H81 = CohomologyRing(81,14, from_scratch=True)
        sage: H81.make(7)
        sage: H81.next()

    We find filter regular parameters that would allow the original form of Benson’s test (see [Benson]) to apply in degree \(5+3+1=9\). We don’t find smaller algebraically independent parameters, but there are algebraically dependent parameters in rather small degree, so that the completeness can be proved using the [Symonds] criterion:

        sage: H81.filter_regular_parameters()
        ['c_6_8', 'b_4_5-b_2_4^2-b_2_3^2']
        sage: H81.parameters()
        ['c_6_8', 'b_4_5-b_2_4^2-b_2_3^2']
        sage: H81.dependent_parameters()
        ['a_1_0', 'a_1_1', 'a_1_2', 'c_6_8', 'b_2_3', 'b_2_4']
        sage: CohomologyRing.global_options('info')
        sage: H81.test_for_completion()
        H^*(E27*C9; GF(3)):
            Trying Symonds' criterion
            Successful application of the Symonds criterion
        True

    Note that the modified Benson criterion of [GreenKing] applies in degree eight as well:

        sage: H81.BensonTest(H81.filter_regular_parameters(),[6,4])
            Testing whether it makes sense to try Benson's completeness criterion
            It is possible that Benson's degree bound applies
            Compute raw_filter_degree_type
            Test filter regularity
              Filter degree type: [-1, -2, -2]
        True
        sage: CohomologyRing.global_options('warn')
        sage: H81.WhatFRS
        (1, 2)

    By the last line, it is possible to replace one (namely the last) parameter by an element of degree two, over a finite extension of the field of coefficients. This suffices for the modified Benson criterion.

  `trait_names`()

    Implement tab completion.

    TESTS:

        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: import sage.interfaces.tab_completion as tc
        sage: 'H.filter_degree_type' in tc.completions('H.f',globals())  # indirect doctest
        True

  `verify_parameters_exist`()

    Test whether the current ring approximation contains a HSOP for the cohomology ring.

    THEORY:

    The ring approximation contains a HSOP for the cohomology ring if and only if the cohomology rings of the maximal elementary abelian subgroups are finitely generated modules over the restriction of the ring approximation.

    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(1)
        sage: print(H)
        Cohomology ring of Dihedral group of order 8 with coefficients in GF(2)
        <BLANKLINE>
        Computed up to degree 1
        Minimal list of generators:
        [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:
        []

    This ring is of Krull dimension two, which coincides with the dimension of the cohomology ring of `SmallGroup(8,3)` (which is the dihedral group with 8 elements). But the ring approximation does not contain parameters for the cohomology ring, yet:

        sage: H.verify_parameters_exist()
        False

    Indeed, the restrictions of the current generators to any of the two maximal elementary abelian subgroups is only of Krull dimension one:

        sage: H.restrictions_as_string(2)
        ['0', 'c_1_1']
        sage: H.restrictions_as_string(3)
        ['c_1_1', '0']

    Hence, we have to compute one step further, and then succeed:

        sage: H.next()
        sage: H.verify_parameters_exist()
        True
        sage: H.parameters()
        ['c_2_2', 'b_1_1+b_1_0']

class `pGroupCohomology.cohomology.` `COHO_Terminator`(S, prefix)

  Remove cohomology data from the Singular interface.

  This is an auxiliary class, with the purpose to remove all data from the Singualar interface that are related with a certain cohomology ring.

  Each cohomology ring has a member that is an instance of this class. Hence, when the ring is deleted then the member’s `__del__` method is called, which clears the Singular interface.

  The somewhat hidden reason for introducing an auxiliar class is that circular references of cohomology rings can not be avoided; hence, if they had a `__del__` method, they could never be garbage collected (the reason is described in the Python references); hence, we moved the `__del__` method to here.

  TESTS:

      sage: from pGroupCohomology.cohomology import COHO_Terminator
      sage: T = COHO_Terminator(singular(1), 'MyPrefix')
      sage: singular.eval('ring MyPrefixR = 0,(a,b,c),dp')
      ''
      sage: print(singular.eval('MyPrefixR'))
      // coefficients: QQ
      // number of vars : 3
      //        block   1 : ordering dp
      //                  : names    a b c
      //        block   2 : ordering C
      sage: singular.eval('ideal MyPrefixI = a^2,b^2,c')
      ''
      sage: print(singular.eval('MyPrefixI'))
      MyPrefixI[1]=a2
      MyPrefixI[2]=b2
      MyPrefixI[3]=c
      sage: del T
      sage: singular('MyPrefixI')
      Traceback (most recent call last):
      ...
      TypeError: Singular error:
         ? `MyPrefixI` is undefined
         ? error occurred in ...

class `pGroupCohomology.cohomology.` `COHO_prefix`

  COHO_prefix()() returns the next safe prefix.

  Used for naming Singular interface data of a `COHO` instance.

  TESTS:

      sage: from pGroupCohomology.cohomology import COHO_prefix
      sage: COHO_prefix.instance=0  # initialization, for avoiding other doc tests to interfere
      sage: COHO_prefix()()
      'COHO1'
      sage: COHO_prefix()()
      'COHO2'

`pGroupCohomology.cohomology.` `COHO_unpickle`(GroupKey, StateFile)

  Unpickling of a cohomology ring.

  TESTS:

      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 is loads(dumps(H)) # indirect doctest
      True

`pGroupCohomology.cohomology.` `FilterDegreeType`(dv, rt)

  Compute the filter degree type.

  INPUT:

  - `d` - list of degrees (\(n\) integers) of a filter regular homogeneous system of parameters, and

  - `r` - the ‘raw filter degree type’ (list of \(n+1\) integers) of these parameters.

  OUTPUT:

  The filter degree type, a list of integers

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import FilterDegreeType
      sage: d=[8,4,6,4]
      sage: r=[-1,4,7,14,18]
      sage: FilterDegreeType(d,r)
      [-1, -2, -3, -4, -4]
      sage: d=[8,4,6,3]
      sage: FilterDegreeType(d,r)
      [-1, -2, -3, -3, -3]

class `pGroupCohomology.cohomology.` `GapPickler`(G)

  This is an auxiliary class for pickling data involving the libgap interface.

  NOTE:

  The only purpose of an instance of this class is to carry a string that allows for reconstruction of an object in Gap. Applying `pickle_gap_data()` to data will work recursively on dictionaries, lists and tuples, and will return most other data unchanged. But when it encounters an object in Gap, it will try whether the object can be reconstructed from its string representation. If this is the case, then it returns an instance of `GapPickler`. When `unpickle_gap_data()` is applied to the result, then it will create an object in Gap in lieue of any string that is stored in a `GapPickler` class.

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import GapPickler, unpickle_gap_data, pickle_gap_data
      sage: G = libgap.SmallGroup(8,3).IsomorphismPermGroup().Image()
      sage: D = {(1, G, "abc"):5}
      sage: unpickle_gap_data(pickle_gap_data(D)) == D  # indirect doctest
      True

`pGroupCohomology.cohomology.` `HV2Poly`(L)

  Translate a list of integers into a univariate polynomial, using the given integers as coefficients.

  INPUT:

  `L`: a list of integers

  OUTPUT:

  A univariate polynomials with coefficients given by `L`

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import HV2Poly
      sage: HV2Poly([3,2,4])
      4*t^2 + 2*t + 3

`pGroupCohomology.cohomology.` `Mul`(L, L0)

  Compute the product of a list of elements, bracketed from the right.

  INPUT:

  - `[L_1,...,L_n]`, a list of elements that can be multiplied

  - `L_0`, an element

  OUTPUT:

  The product `(L_1...*(L_{n-1}*(L_n*L_0))...)`

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import Mul
      sage: M=Matrix(GF(5),[[1,2],[1,1]])
      sage: M1=Matrix(GF(5),[[1,2],[1,1]])
      sage: M2=Matrix(GF(5),[[1,3],[2,1]])
      sage: M3=Matrix(GF(5),[[1,4],[3,1]])
      sage: Mul([M1,M2],M3)
      [0 0]
      [0 1]
      sage: Mul([M2,M3],M1)
      [2 2]
      [4 4]
      sage: M2*M3*M1==Mul([M2,M3],M1)
      True

`pGroupCohomology.cohomology.` `explore_one_parameter`(Id, L0, p, BreakPoint=None, regularity=0, H1=None, is_monomial=True)

  Find a parameter for the quotient ring given by an ideal.

  INPUT:

  - `Id` – Ideal in a graded commutative ring of prime characteristic \(p\).

      Must be a Groebner basis.

  - `L0` – a list of homogeneous elements (given by strings) of the same degree.

  - `p` – a prime.

  - `BreakPoint` – (optional integer or infinity) test at most that many candidates

      for a parameter (default: infinity).

  - `regularity` – (optional int, default `0`) If `1` (not default), find

      a parameter that is filter regular modulo `Id`. If `2`, find a parameter that is regular modulo `Id`.

  - `H1` – (optional) the Hilbert Poincaré series of `Id`.

  - `is_monomial` – (optional) whether the element in `L0` are monomials.

  OUTPUT:

  - 1. An element \(v\) in Singular that lowers the dimension of `Id` by one (aka “parameter” for `Id`),

    2. A tuple of integers, namely the list of coefficients that defines `v` as linear combination of the monomials in `L`.

    3. The return value of `is_filter_regular`, if `regularity==1`, or `[]`.

  - `False, False, []`, if no linear combination of elements of `L` provides a parameter for `Id`, or

  - `None, None, []`, if the search for a parameter was stopped since the number of candidates exceeded `BreakPoint`.

  NOTE:

  If \(is_monomial\) is true, then only lineare combinations of the standard monomials in `L0` relative to `Id` will be considered.

  TESTS:

      sage: from pGroupCohomology import CohomologyRing
      sage: from pGroupCohomology.cohomology import explore_one_parameter
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(32,33)
      sage: H.make()
      sage: H.set_ring()
      sage: Id = H.relation_ideal()
      sage: L = H.standard_monomials(3)
      sage: explore_one_parameter(Id,L,2)
      (b_1_0^3, (0, 0, 0, 0, 0, 0, 0, 1, 0, 0), [])
      sage: explore_one_parameter(Id,L,2, regularity=1)
      (False, False, [])
      sage: Id.dim()
      3
      sage: Id.std('b_1_0^3').dim()
      2

  Now, we use two non-commutative examples. We do not need to distinguish Singular versions 3-1-1 and older versions, since in this example there are regular respectively filter-regular parameters.

      sage: H = CohomologyRing(27,4)
      sage: H.make()
      sage: H.dimension()
      2
      sage: H.depth()
      1
      sage: H.set_ring()
      sage: Id = H.relation_ideal()
      sage: L = H.standard_monomials(6)
      sage: explore_one_parameter(Id,L,3,regularity=2)
      (c_6_2, (0, 0, 0, 0, 0, 1), [0])
      sage: Id = Id.std('c_6_2')
      sage: L = H.standard_monomials(2)
      sage: explore_one_parameter(Id,L,3)
      (b_2_1, (0, 0, 1, 0), [])
      sage: explore_one_parameter(Id,L,3,regularity=1)
      (b_2_1, (0, 0, 1, 0), [0, 1, 1, 1, 1])
      sage: explore_one_parameter(Id,L,3,regularity=2)
      (False, False, [])

`pGroupCohomology.cohomology.` `is_filter_regular`(I, f, H1=None, I2=None)

  Test if \(f\) is filter-regular with respect to \(I\).

  INPUT:

  - \(I\), complete standard basis of a weighted homogeneous ideal; Singular element or string.

  - \(f\), weighted homogeneous element; Singular element or string.

  - \(H1\) (optional) – first Hilbert Poincaré series of \(I\), if that has already been computed

  - \(I2\) (optional) – `std(I,f)`, if that has already been computed

  OUTPUT:

  Finite list of vector space dimensions of the annulator of \(f\) with respect to \(I\), i.e., \(\{p|f\cdot p\in I\}\), or `False` if the annulator is not finite dimensional.

  EXAMPLES:

      sage: from pGroupCohomology import CohomologyRing
      sage: from pGroupCohomology.cohomology import is_filter_regular
      sage: CohomologyRing.doctest_setup()
      sage: H = CohomologyRing(64, 23, from_scratch=True)
      sage: H.make(4)
      sage: F = H.filter_regular_parameters()
      sage: is_filter_regular(H.relation_ideal(), F[0])
      False
      sage: is_filter_regular(H.relation_ideal().std(F[1]), F[0])
      [0]
      sage: is_filter_regular(H.relation_ideal().std(F[0]).std(F[1]).std(F[2]), F[3])
      False
      sage: H.make()
      sage: is_filter_regular(H.relation_ideal().std(F[0]).std(F[1]).std(F[2]), F[3])
      [0, 2, 1, 1, 2]

`pGroupCohomology.cohomology.` `is_filter_regular_parameter_system`(I, FRS)

  Test if \(FRS\) is a filter-regular parameter system with respect to \(I\).

  INPUT:

  - \(I\), complete standard basis of a weighted homogeneous ideal; Singular element or string.

  - \(FRS\), an iterable of Singular elements or strings representing weighted homogeneous elements.

  OUTPUT:

  `False`, or the raw filter degree type, which is a list of `len(FRS)+1` lists of integers: The \(i\)-th list provides the vector space dimensions of each degree layer of the annulator of the \(i\)-th element of \(FRS\) modulo the preceeding elements; the last list provides the vector space dimensions of each degree layer of the quotient modulo \(FRS\). If some annulator or the final quotient is not finite dimensional, then `False` is returned.

  EXAMPLES:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()
      sage: H = CohomologyRing(64, 23, from_scratch=True)
      sage: H.make(4)

  There exists a set of elements of degree at most four that are guaranteed to form a filter regular system of parameters of the cohomology ring:

      sage: F = H.filter_regular_parameters()
      sage: F
      ['c_2_4', 'c_4_14', 'b_2_3+b_2_2+b_2_1', 'b_3_6']

  However, they are not filter regular in the ring approximations out to degree 4 or 7. They are filter regular in the ring approximation out to degree 8, and this is in fact the complete cohomology ring:

      sage: from pGroupCohomology.cohomology import is_filter_regular_parameter_system
      sage: is_filter_regular_parameter_system(H.relation_ideal(), F)
      False
      sage: H.make(7)
      sage: is_filter_regular_parameter_system(H.relation_ideal(), F)
      False
      sage: H.make(8)
      sage: is_filter_regular_parameter_system(H.relation_ideal(), F)
      [[0], [0], [0], [0, 2, 1, 1, 2], [1, 2, 3, 4, 5, 2, 0, 1]]
      sage: H.completed
      True

class `pGroupCohomology.cohomology.` `permanent_result`(f)

  Cache a method and reconstruct data in interfaces when needed.

  NOTE:

  The value `None` will not be cached.

  The decorator only works if it is used for a method of an instance `X` that either has an attribute `_decorator_cache` (a dictionary) or allows its creation.

  If the result is in the Singular interface and Singular crashes, then sometimes it is necessary for reconstruction of data that `X` has an attribute `GenS` whose parent is Singular, and it needs to have an interpretation in Singular.

  If the method arguments are in an interface then it is imperative that they can be reconstructed from its string representation.

  If the method raised a `KeyboardInterrupt`, this is cached as well, but a new computation can be attempted with the optional argument `forced` added to the method’s arguments. Note that `forced` is not passed as an argument to the underlying function.

  NOTE:

  Sometimes, the results stored with this decorator involve data defined in GAP. GAP does by default not provide data serialisation, and even GAP’s optional IO package would only write data directly to a file object, which is awkward when otherwise relying on Python’s pickling protocols. However, often a GAP object can be reconstructed from its string representation, and that’s what we are using here.

  ASSUMPTION:

  If the result is in the Singular interface, it is assumed that `singular(X).set_ring()` is possible and that the result either belongs to this ring or is ring independent.

  EXAMPLES:

  This decorator is designed for use in cohomology rings, but the examples show that it works more generally:

      sage: from pGroupCohomology.cohomology import permanent_result
      sage: class FOO:
      ....:   def __init__(self,R):
      ....:       self.R = R
      ....:       self.GenS = singular.int(1)
      ....:   def _singular_(self,S):
      ....:       return S(self.R)
      ....:   @permanent_result
      ....:   def bar(self, G):
      ....:       '''
      ....:       Here is the documentation.
      ....:       '''
      ....:       singular(self).set_ring()
      ....:       print('Group of order',G.Order())
      ....:       return singular.maxideal(G.Order())
      sage: R.<x,y> = QQ[]
      sage: f = FOO(R)
      sage: G2 = libgap.eval('Group( [ (1,2) ] )')
      sage: G3 = libgap.eval('Group( [ (1,2,3) ] )')

  It can be seen from the printed statement that the actual computation is only done when the method is called first.

      sage: I2 = f.bar(G2); I2
      Group of order 2
      y^2,
      x*y,
      x^2
      sage: f.bar(G2)
      y^2,
      x*y,
      x^2
      sage: I3 = f.bar(G3); I3
      Group of order 3
      y^3,
      x*y^2,
      x^2*y,
      x^3
      sage: f.bar(G3)
      y^3,
      x*y^2,
      x^2*y,
      x^3
      sage: I2 is f.bar(G2)
      True

  The point is that even when Singular crashes, the data can be reconstructed without a new computation (note that the printed statement does not appear):

      sage: singular.quit()
      sage: G2 = libgap.eval('Group( [ (1,2) ] )')
      sage: f.bar(G2)
      y^2,
      x*y,
      x^2
      sage: I2 is f.bar(G2)
      False
      sage: I2 = f.bar(G2)

  Note, moreover, that the given doc string is modified by the decorator:

      sage: print(f.bar.__doc__)
      Permanently cached method: Here is the documentation.
      <BLANKLINE>

  Last, we simulate a `KeyboardInterrupt` being cached, and force recomputation afterwards:

      sage: f.bar.set_cache(KeyboardInterrupt('simulation'),G2)
      sage: try:
      ....:     f.bar(G2)
      ....: except KeyboardInterrupt as msg:
      ....:     print(msg)
      simulation
      sage: f.bar(G2, forced=True)
      Group of order 2
      y^2,
      x*y,
      x^2
      sage: I2 is f.bar(G2)
      False

  Note that when a `KeyboardInterrupt` really occurs in the method, the error message will mention the possibility of forcing a recomputation. Here is an example:

      sage: class FOO:
      ....:     _t = 0
      ....:     @permanent_result
      ....:     def bar(self, n):
      ....:         if not self._t:
      ....:             raise KeyboardInterrupt
      ....:         return n+self._t
      ....:     @permanent_result
      ....:     def foo(self,n):
      ....:         return libgap.SymmetricGroup(self.bar(n))
      sage: f = FOO()
      sage: try:
      ....:     f.foo(1)
      ....: except KeyboardInterrupt as msg:
      ....:     print(msg)
      bar interrupted. Force re-computation at <....FOO ... at ...> with ``forced=True``
      foo interrupted. Force re-computation at <....FOO ... at ...> with ``forced=True``

  The `KeyboardInterrupt` is cached. So, even if we set the attribute `_t` above to a non-zero value, the error won’t go away, unless we force re-computation:

      sage: f._t = 2
      sage: try:
      ....:     f.bar(1)
      ....: except KeyboardInterrupt as msg:
      ....:     print(msg)
      bar interrupted. Force re-computation at <....FOO ... at ...> with ``forced=True``
      sage: f.bar(1, forced=True)
      3
      sage: try:
      ....:     f.foo(1)
      ....: except KeyboardInterrupt as msg:
      ....:     print(msg)
      bar interrupted. Force re-computation at <....FOO ... at ...> with ``forced=True``
      foo interrupted. Force re-computation at <....FOO ... at ...> with ``forced=True``
      sage: f.foo(1,forced=True)
      Sym( [ 1 .. 3 ] )

  In the next example, we demonstrate that pickling works, even if Gap data are involved:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(184,5, prime=2)
      sage: H.make()
      sage: type(H.essential_ideal)
      <class 'pGroupCohomology.cohomology.permanent_result'>
      sage: H.essential_ideal([H.group().SylowSubgroup(2).Centre()])
      b_1_0,
      b_1_1

  Now, we store the result on disc, empty the cache, reload, and demonstrate by logging that the previously computed result has been stored, even though the data are defined in the Singular interface and are indexed by an object in Gap:

      sage: save(H, H.autosave_name())
      sage: CohomologyRing._cache.clear()
      sage: CohomologyRing.global_options('warn')
      sage: H2 = load(H.autosave_name())
      sage: H2 is H
      False
      sage: H2.essential_ideal([H.group().SylowSubgroup(2).Centre()])
      b_1_0,
      b_1_1
      sage: CohomologyRing.global_options('warn')
      sage: H.group().SylowSubgroup(2).Centre().parent()
      C library interface to GAP
      sage: H2.essential_ideal([H.group().SylowSubgroup(2).Centre()]).parent()
      Singular

  `get_cache`(*args, **kwds)

    Return the value that was saved using `set_cache()`.

    NOTE:

    If necessary, data in interfaces (in particular in GAP and Singular) are reconstructed. This of course only works to some extent (e.g., for GAP, it is needed that the saved value can be reconstructed from its string representation, and in Singular, it needs to be reconstructible from the string representation and the type information.

    EXAMPLE:

        sage: from pGroupCohomology.cohomology import permanent_result
        sage: class FOO:
        ....:     GenS = singular.int(0) # needed for Singular reconstruction
        ....:     def _singular_(self, S):
        ....:         return S(QQ['x','y'])
        ....:     @permanent_result
        ....:     def bar(self, n):
        ....:         return libgap.SymmetricGroup(n)
        ....:     @permanent_result
        ....:     def foo(self, n):
        ....:         singular(self).set_ring()
        ....:         return singular.maxideal(n)
        sage: f = FOO()
        sage: f = FOO()
        sage: G = f.bar(4); G
        Sym( [ 1 .. 4 ] )
        sage: G is f.bar(4)
        True

    Setting the cache to a different value:

        sage: f.bar.set_cache(gap.AlternatingGroup(3), 4)
        sage: f.bar(4)
        AlternatingGroup( [ 1 .. 3 ] )
        sage: f.bar.get_cache(4)
        AlternatingGroup( [ 1 .. 3 ] )

    Now, similarly for data in Singular:

        sage: I = f.foo(3); I
        y^3,
        x*y^2,
        x^2*y,
        x^3
        sage: I is f.foo(3)
        True
        sage: f.foo(3).typeof()
        ideal
        sage: f.foo.set_cache(singular.poly('x*y'),3)
        sage: f.foo.get_cache(3)
        x*y
        sage: f.foo(3).typeof()
        poly

  `set_cache`(val, *args, **kwds)

    Set the cache for the given arguments to a certain value.

    INPUT:

    - `val` – any object, that is to be cached

    - Any position and keyword arguments. They must be immutable or lists of immutables.

    EXAMPLE:

        sage: from pGroupCohomology.cohomology import permanent_result
        sage: class FOO:
        ....:     @permanent_result
        ....:     def bar(self, G):
        ....:         return G.Order()
        ....:     @permanent_result
        ....:     def foo(self, G):
        ....:         raise KeyboardInterrupt
        sage: f = FOO()
        sage: G2 = libgap.eval('Group( [ (1,2) ] )')
        sage: f.bar(G2)
        2
        sage: try:
        ....:     f.foo(3)
        ....: except KeyboardInterrupt as msg:
        ....:     print(msg)
        foo interrupted. Force re-computation at <....FOO ... at ...> with ``forced=True``

    This results in creating a cache for `f`. Note that even the `KeyboardInterrupt` is cached:

        sage: sorted(f._decorator_cache.items())    #indirect doctest
        [(('bar', Group([ (1,2) ])), [2]),
         (('foo', 3),
          [KeyboardInterrupt('foo interrupted. Force re-computation ...)])]

`pGroupCohomology.cohomology.` `pickle_gap_data`(G)

  Pickle data involving objects in Gap.

  INPUT:

  `G`: Any object.

  NOTE:

  Applying this function to data will work recursively on dictionaries, lists and tuples, and will return most other data unchanged. But when it encounters an object in Gap, it will try whether the object can be reconstructed from its string representation. If this is the case, then it returns an instance of `GapPickler`. When `unpickle_gap_data()` is applied to the result, then it will create an object in Gap in lieue of any string that is stored in a `GapPickler` class.

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import GapPickler, unpickle_gap_data, pickle_gap_data
      sage: G = libgap.SmallGroup(8,3).IsomorphismPermGroup().Image()
      sage: D = {(1, G, "abc"):(5,G)}
      sage: unpickle_gap_data(pickle_gap_data(D)) == D
      True

  If Gap data can not be reconstructed from its string representation, a type error is raised:

      sage: G = libgap.SmallGroup(8,3)
      sage: D = {(1, G, "abc"):5}
      sage: pickle_gap_data(D)
      Traceback (most recent call last):
      ...
      TypeError: Can not pickle 'Group( [ f1, f2, f3 ] )'

`pGroupCohomology.cohomology.` `str2html`(s, linelength=80)

  HTML representation of a string representation of a polynomial.

  INPUT:

  - `s` - a string representing a polynomial

  - `linelength=80` - (optional) approximate line length of the output

  OUTPUT:

  HTML representation of the polynomial (string). If the polynomial is too long, there will be line breaks.

  NOTE:

  - It is expected that all exponents are positive integer numbers, written without signs.

  - The multiplication sign ‘*’ is replaced by ‘&middot;’

  - In order to group the terms nicely, there is a small space around plus and minus signs.

  - There is an indentation after a line break.

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import str2html
      sage: R.<x,y>=QQ[]
      sage: s=str(x^2+2*x*y+y^4)
      sage: s
      'y^4 + x^2 + 2*x*y'
      sage: str2html(s)
      '<nobr>y<sup>4 </sup>&thinsp;+&thinsp; x<sup>2 </sup>&thinsp;+&thinsp; 2&middot;x&middot;y</nobr>'

  If we choose a very small line length, the result breaks into several lines:

      sage: str2html(s,linelength=15)
      '<nobr>y<sup>4 </sup>&thinsp;+&thinsp; x<sup>2 </sup></nobr><br>&nbsp;&nbsp;<nobr>&thinsp;+&thinsp; 2&middot;x&middot;y</nobr>'

class `pGroupCohomology.cohomology.` `temporary_result`(f)

  Decorator for caching methods of a cohomology ring approximation.

  NOTE:

  This decorator is designed for application to cohomology rings (`COHO`). Unlike `permanent_result`, the cached value is re-computed if the structure of the ring approximation has changed, i.e., if a new generator or a new relation was found after the value was cached.

  `KeyboardInterrupt` is cached – see `permanent_result` for more details.

  EXAMPLE:

  The method `poincare_series()` uses our decorator for temporary results. In order to avoid using a stored value, we force a new computation in the first place.

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H = CohomologyRing(8,4, from_scratch=True)
      sage: H.make(1)
      sage: CohomologyRing.global_options('info')
      sage: p = H.poincare_series(); p   # indirect doctest
      H^*(Q8; GF(2)):
          Compute poincare_series
          Computing complete Groebner basis
      1/(t^2 - 2*t + 1)
      sage: p is H.poincare_series()
      True

  We now overwrite the cached value, also demonstrating that a `KeyboardInterrupt` is cached as well:

      sage: H.poincare_series.set_cache(KeyboardInterrupt('bla'))
      sage: try:
      ....:     H.poincare_series()
      ....: except KeyboardInterrupt as msg:
      ....:     print(msg)
      bla

  We can use the optional argument `forced` for restoring the cache:

      sage: H.poincare_series(forced=True)
          Forced recomputation of poincare_series
          Compute poincare_series
      1/(t^2 - 2*t + 1)

  The value in the cache is automatically updated if the ring structure changes by a computation in higher degree. The use of the optional argument `forced` is not necessary in this case:

      sage: CohomologyRing.global_options('warn')
      sage: H.make(2)
      sage: CohomologyRing.global_options('info')
      sage: H.poincare_series()
      H^*(Q8; GF(2)):
          Compute poincare_series
      (t + 1)/(-t + 1)

  `get_cache`(*args, **kwds)

    Get the value that was cached for the given arguments.

    NOTE:

    If the ring structure has changed after storing the value, a `KeyError` is raised.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,4, from_scratch=True)
        sage: H.make(1)
        sage: p = H.poincare_series(); p
        1/(t^2 - 2*t + 1)
        sage: p is H.poincare_series.get_cache()
        True
        sage: H.make(2)
        sage: H.poincare_series.get_cache()
        Traceback (most recent call last):
        ...
        KeyError: 'The saved data belong to a previous stage of the computation'

  `set_cache`(val, *args, **kwds)

    Set the cache of this method to a specific value.

    INPUT:

    - `val` – the value to be cached.

    - Any further position or keyword arguments that are suitable as dictionary keys (lists are automatically transformed into tuples).

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,4, from_scratch=True)
        sage: H.make(1)
        sage: H.poincare_series()
        1/(t^2 - 2*t + 1)
        sage: H.poincare_series.set_cache('hello world',42,foo='bar')
        sage: H.poincare_series(42, foo='bar')
        'hello world'
        sage: H.poincare_series(42, foo='bar', forced=True)
        Traceback (most recent call last):
        ...
        TypeError: poincare_series() got an unexpected keyword argument 'foo'
        sage: H.poincare_series(42, foo='bar')
        'hello world'

    Note that the cache is automatically cleared if the ring structure changes:

        sage: H.make()
        sage: H.poincare_series(42, foo='bar')
        Traceback (most recent call last):
        ...
        TypeError: poincare_series() got an unexpected keyword argument 'foo'
        sage: H.poincare_series()
        (-t^2 - t - 1)/(t^3 - t^2 + t - 1)

`pGroupCohomology.cohomology.` `unpickle_gap_data`(G)

  Unpickle data involving objects in Gap.

  INPUT:

  - `G`: Any object.

  NOTE:

  Applying `pickle_gap_data()` to data will work recursively on dictionaries, lists and tuples, and will return most other data unchanged. But when it encounters an object in Gap, it will try whether the object can be reconstructed from its string representation. If this is the case, then it returns an instance of `GapPickler`. When this function is applied to the result, then it will create an object in Gap in lieue of any string that is stored in a `GapPickler` class.

  EXAMPLES:

      sage: from pGroupCohomology.cohomology import GapPickler, unpickle_gap_data, pickle_gap_data
      sage: G = libgap.SmallGroup(8,3).IsomorphismPermGroup().Image()
      sage: D = {(1, G, "abc"):5}
      sage: unpickle_gap_data(pickle_gap_data(D)) == D
      True