Constructing Cohomology Rings — "p_group_cohomology" 3.3.2 documentation

# Constructing Cohomology Rings

AUTHORS:

- Simon King <simon.king@uni-jena.de> (Cython and Python code, porting, maintainance)

- David Green <david.green@uni-jena.de> (underlying C code)

This module provides a constructor for modular cohomology rings of finite groups, that takes care of caching. The constructor is an instance `CohomologyRing()` of the class `CohomologyRingFactory`.

`pGroupCohomology.factory.` `CohomologyRing`(*args, **kwds)

  Constructor for modular cohomology rings of finite groups.

  This constructor is an instance of `CohomologyRingFactory`. See there and see `pGroupCohomology` for more examples.

  The constructor can be called directly. Then, it is first checked whether the completely computed cohomology ring of the given group is part of some database, or whether it can be downloaded. If this is not the case, a new cohomology ring is created, being part of the user’s workspace.

  Using `set_workspace()`, the location of the user’s workspace can be changed. By `from_workspace()`, one can explicitly ask for taking data from the workspace. The input formats for calling `CohomologyRing()` and for calling `from_workspace()` or `from_local_sources()` are the same.

  INPUT:

  Parameters describing the group

  - A finite group \(G\) , either

    - given by an integer `q` and a positive number `n`, determining an entry of the SmallGroups library, or

    - given as an object in the libgap interface

  - `GroupName` (optional string): a name for the group. If the group \(G\) is given in the Gap interface and if it is not provided with a custom name (using libGap’s `SetName`) then `GroupName` must be provided.

  - `GroupDescr` (optional string): a description of the group. This can be any string, and is used when printing the cohomology ring or creating a web-site for it.

  - If the group is not of prime power order, the optional parameter `prime` must be set to a prime number.

  Parameters describing the database

  - `websource`: If it is `False`, it is not attempted to download data from a web repository. If it is a URL (string) or tuple of URLs providing the location(s) of a database in the web, then it is attempted to download the data from there. If `websource` is not given then first it is tried to look up data in the local file system, and if this fails then it is attempted to download the data from some default location in the web.

  - `from_scratch` (default `False`): If it is `True`, this cohomology ring may be taken from the cache or from the workspace, but will not be copied from local or remote sources. Note that this will only take effect on this single ring; cohomology rings of subgroups, occuring during the computation, will still be loaded.

  Parameters modifying the algorithm

  - `useElimination` (optional, default `None`): If `True`, the elimination method is used for trying to construct the Dickson classes. If `False`, the linear algebra method is used for that purpose. By default, the linear algebra method is chosen, unless there is a Dickson class in degree greater than 18 (for prime power groups) or 20 (for non prime power groups).

  - `DicksonExp` (optional integer, default = 3): If the elimination method for finding the Dickson classes is used, it is needed to set a bound for the power to which the Dickson classes might be raised: If \(G\) is a \(p\)-group and \(n\) is the given `DicksonExp`, then the Dickson classes of the elementary abelian sub-groups of \(G\) are raised to the power of \(p^0,p^1,...,p^n\) before trying to simultaneously lift them to \(G\). We do not know any example in which the default value would not suffice.

  - `useFactorization` (optional boolean, default True): Try to replace the Dickson classes of \(G\) by their minimal non-constant factors. This may simplify some computations, but there are rare examples in which the factorisation is a bigger problem than a high degree bound.

  - `auto` (optional integer, default = 2 for abelian groups, and = 4 otherwise): Only applies to the case of prime power groups. A quick but potentially memory consuming method for lifting chain maps will be used in degree at most `auto`. For prime power groups up to orders around 500, the default value seems to be heuristically best.

  - `useSlimgb` / `useStd` (optinal boolean): Use Singular’s `slimgb` (resp. `std`) for computing the Groebner basis of the relation ideal. If not specified, Singular’s `groebner` method is chosen, which uses a heuristics to find the best algorithm for the computation of the Groebner basis.

  Global options

  - `options` (optional string or list of strings): set/unset global options, or a dictionary that the global options are updated with.

  There are various global options—they apply to all cohomology rings. Each option is set by a string, and unset by prepending `'no'` to that string.

  > Available options

  > - `'warn'` [default], `'info'`, `'debug'`, logging level

  > - `'useMTX'` [default], use `Matrix_gfpn_dense` matrices for linear algebra over finite fields, which rely on SharedMeatAxe. Note that the resolutions will always be computed using the SharedMeatAxe. By consequence, if `useMTX` is turned off, time is wasted for conversions between different matrix types.

  > - `'save'` [default], automatically save ring approximations, which comes in very handy when a long computation needs to be interrupted at some point; that’s why it is the default. Note that many data, including a minimal projective resolution for prime power groups, will always be stored on disk.

  > - `'sparse'` [not default], remove temporarily unneeded data on the resolution from memory. With that option, the computation of very large examples becomes more feasible.

  > Further options have a numerical value:

  > - `autolift` [default=1]: Degree up to which cochains are lifted using the autolift (as opposed to the Urbild Gröbner basis) method. Only applies to groups that are not elementary abelian.

  > - `autoliftElAb` [default=0]: The same as `autolift`, but for elementary abelian groups.

  > - `SingularCutoff` [default=70]: This determines how commands for Singular are cut into pieces, in order to reduce the overhead of the pexpect interface.

  > - `NrCandidates` [default=1000]: Maximal number of candidates that are considered when trying to find special elements (e.g., parameters) by enumeration.

  In experiments with `unit_test_64()`, the different options had the following effect:

  - With `options="nouseMTX"`, the computation time slightly increases.

  - With `options="sparse"`, the computation time increases.

  - With `options="nosave"`, the computation time decreases.

  The options can also be (un)set later, by using the method `global_options()`.

class `pGroupCohomology.factory.` `CohomologyRingFactory`

  A factory for creating modular cohomology rings of finite p-groups as unique parent structures

  Please use `CohomologyRing()`, which is an instance of this class, and is provided with a documentation of the available options.

  TESTS:

      sage: from pGroupCohomology import CohomologyRing
      sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
      sage: H0 = CohomologyRing(8,3)   #indirect doctest
      sage: print(H0)
      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]

  `check_arguments`(args, minimal_generators=None, GroupId=None)

    Return group order and a group in GAP with generating set suitable for the computations

    INPUT:

    - `args`: A list, either formed by a group in GAP or by two integers, providing an address in the SmallGroups library.

    - `minimal_generators`: (optional bool) If it is true, it is asserted by the user that an initial segment of the given list of generators of the group froms a minimal generating set.

    - `GroupId`: (optional) Pair of numbers, providing the address of the given group in the SmallGroups library, if this happens to be known to the user.

    OUTPUT:

    - The group order, and

    NOTE:

    - It only matters in the case of prime power groups whether or not the given list of generators starts with a minimal generating set.

    - If the optional argument `GroupId` is provided, it is verified whether the group from the SmallGroups library is equivalent to the given group.

    EXAMPLE:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.check_arguments([8,3])
        (8, <pc group of size 8 with 3 generators>)
        sage: CohomologyRing.check_arguments([libgap.eval('DihedralGroup(8)')])
        (8, Group([ (1,2)(3,8)(4,6)(5,7), (1,3,4,7)(2,5,6,8) ]))
        sage: CohomologyRing.check_arguments([libgap.eval('DihedralGroup(8)')], GroupId=[8,3])
        Traceback (most recent call last):
        ...
        ValueError: The given group generators are not canonically isomorphic to SmallGroup(8,3)

  `create_group_key`(G, GroupId=None, GroupDefinition=None)

    Return data that allow to determine a given group up to equivalence.

    NOTE:

    For our package, a group is always supposed to be provided with a fixed list of generators. Two groups are equivalent if there exists a group homomorphism that sends the list of generators of one group to an initial segment of the list of generators of the other group. The ring presentation of a cohomology ring of a group, as computed with this package, only depends on the group’s equivalence class.

    This is nothing more than an auxiliary method.

    INPUT:

    - `G` - a list, either formed by two integers representing an address in the SmallGroups library, or formed by a group in the libGAP interface.

    - `GroupId` - optional list of two integers, that is supposed to provide the address of a group in the SmallGroups library equivalent to the group given by `G`.

    - `GroupDefinition` - optional string, that is supposed to be evaluated in the libGAP interface, yielding a group that is equivalent to the group given by `G`

    OUTPUT:

    - If `GroupDefinition` is provided, it is returned.

    - If the given group is equivalent to a group in the SmallGroups library whose address is either given or can be determined by GAP, then this address (a pair of integers) is returned.

    - Otherwise, if the group is not a permutation group, it is transformed into an equivalent permutation group (using the regular permutation action). Then, a string representation of that permutation group is returned.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing(8,3)
        sage: H.group()
        Group([ (1,2)(3,8)(4,6)(5,7), (1,3)(2,5)(4,7)(6,8) ])
        sage: CohomologyRing.create_group_key([H.group()])
        (8, 3)

    By consequence, the cohomology rings of `SmallGroup(8,3)` and the permutation group above are identic:

        sage: H is CohomologyRing(libgap.eval('SmallGroup(8,3)'))
        True
        sage: H is CohomologyRing(H.group())
        True

    However, defining the dihedral group differently, we obtain a different equivalence class, and thus a different result:

        sage: CohomologyRing.create_group_key([libgap.eval('DihedralGroup(8)')])
        ('Group([(1,2)(3,8)(4,6)(5,7),(1,3,4,7)(2,5,6,8)])',)

    So, the given group is transformed into an equivalent permutation group. If we start with a big transformation group, a string representation obtained from its list of generators is returned:

        sage: CohomologyRing.create_group_key([libgap.eval('SymmetricGroup(8)')])
        ('Group([(1,2,3,4,5,6,7,8),(1,2)])',)

    It is possible to provide a reasonable string representation or a SmallGroups address. However, it is the user’s responsibility to choose values that match the given group - this is not verified, as can be seen in the final example:

        sage: CohomologyRing.create_group_key([libgap.eval('SymmetricGroup(8)')],GroupDefinition='SymmetricGroup(8)')
        'SymmetricGroup(8)'
        sage: CohomologyRing.create_group_key([libgap.eval('SymmetricGroup(8)')],GroupId=[20,2])
        (20, 2)

    TEST:

    It is important that the group key is not formed by two integers in the libGAP interface. Namely, when storing the resulting ring, it could not easily be unpickled (actually it can be unpickled, but this involves some trickery, and it is certainly better to not rely on trickery). Here, we demonstrate that the given keys are correctly converted:

        sage: CohomologyRing.set_workspace(tmp_dir())
        sage: X = CohomologyRing(libgap(8),libgap(3), from_scratch=True)
        sage: type(X._key[0][0])
        <type 'sage.rings.integer.Integer'>

  `doctest_setup`()

    Block web access and put the workspace into a temporary directory.

    This is essential when doctesting computations that would access web repositories of cohomology data.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.reset()
        sage: from pGroupCohomology.cohomology import COHO
        sage: COHO.remote_sources
        ('http://cohomology.uni-jena.de/db/',)
        sage: CohomologyRing.doctest_setup()
        sage: COHO.remote_sources
        ()

  `from_local_sources`(*args, **kwds)

    Retrieve/create a cohomology ring in the local sources

    NOTE:

    - The local sources can be chosen using `set_local_sources()`.

    - Write permissions to the local sources are required in this method.

    - All subsequent computations will modify data in the local sources, until `CohomologyRing.set_local_sources(False)` is used.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: tmp_priv = tmp_dir()
        sage: tmp_publ = tmp_dir()
        sage: CohomologyRing.set_workspace(tmp_priv)

    We demonstrate how to put data into the local sources:

        sage: CohomologyRing.set_local_sources(tmp_publ)
        sage: H1 = CohomologyRing(8,3)
        sage: H1.root.startswith(os.path.realpath(tmp_publ))
        True

    After unsetting it, the user’s workspace is used instead:

        sage: CohomologyRing.set_local_sources(False)
        sage: H2 = CohomologyRing(8,4)
        sage: H2.root.startswith(os.path.realpath(tmp_priv))
        True

    But it is possible to access the local sources directly:

        sage: H3 = CohomologyRing.from_local_sources(8,2)
        sage: H3.root.startswith(os.path.realpath(tmp_publ))
        True

  `from_remote_sources`(GStem, websource=None, prime=None)

    Import a cohomology ring from a web source.

    NOTE:

    Usually this function would not be directly used. It is automatically called by `CohomologyRing()` if a cohomology ring can not be found in a local folder.

    INPUT:

    - `GStem`, a string so that `GStem+'.tar.gz'` can be found in the web source, if it is a prime power group, or `'H'+GStem+'mod%d.sobj'%prime` otherwise.

    - `websource`: If `None` (default), the currently known URLs of web repositories (those provided by `set_remote_sources()`) are chosen. If `False`, no remote source is used. Otherwise, it should be a single URL (string) or tuple of URLs.

    - `prime`: An optional prime, the modulus of the cohomology ring. It must be provided if ond only if the group is not a prime power group.

    NOTE:

    During doctests, the web access is usually switched off,

    TESTS:

    We choose a low logging level, so that it is visible what happens behind the scenes.

        sage: from pGroupCohomology import CohomologyRing
        sage: from sage.env import SAGE_SHARE
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: CohomologyRing.global_options('info')

    During package installation, and thus also during its doctests, web access is blocked. Therefore, we simulate a data base using local files that are available during package installation:

        sage: H = CohomologyRing.from_remote_sources('8gp3', websource='file://'+os.path.join(os.path.realpath(os.path.curdir),'test_data'))
        from_remote_sources:
            Accessing web
            Press Ctrl-c to interrupt web access.
            Downloading and extracting archive file
            Trying to read downloaded data
        Resolution of GF(2)[8gp3]:
            Differential reloaded
            > rk P_02 =   3
            Differential reloaded
            > rk P_03 =   4
        H^*(D8; GF(2)):
            Import monomials
        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]

  `from_subgroup_tower`(*args, **kwds)

    Given a tower of subgroups starting with a Sylow subgroup, compute a cohomology ring with stability conditions associated with that subgroup.

    INPUT:

    - Some nested groups ascendingly sorted starting with a prime power group

    - Keyword arguments similar to the ones of :class: ~pGroupCohomology.factory.CohomologyRingFactory`.

    OUTPUT:

    The cohomology of the last of the given subgroups (without computing the ring structure).

    EXAMPLES:

    Notmally, we compute the mod-\(p\) cohomology of a finite non-primepower group \(G\) as a subring of the cohomology ring of \(N_G(Z(Syl_p(G)))\), which in turn is computed as a subring of the cohomology ring of \(Syl_p(G)\). If one wants to compute the cohomology of \(G\) using a different subgroup tower, this method can be used. The computation of the mod-\(2\) cohomology of the third Conway group, for example, was possible using a tower of four subgroups, which reduced the total number of stability conditions to \(11\). In the following example, we do the opposite and compute the cohomology ring of the alternating group of rank \(8\) without an intermediate subgroup.

    But first, we compute the cohomology in the default way:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()
        sage: A8 = libgap.AlternatingGroup(8)
        sage: SylA8 = A8.SylowSubgroup(2).MinimalGeneratingSet().Group()
        sage: HA8 = CohomologyRing(A8, prime=2, GroupName="A_8")
        sage: HA8.make()

    Here is the non-standard way:

        sage: HA8_direct = CohomologyRing.from_subgroup_tower(SylA8, A8, GroupName="A8", GroupDescr='AlternatingGroup(8)')
        sage: HA8_direct.make()

    Apparently, the ring structures thus computed look different:

        sage: print(HA8)
        Cohomology ring of A_8 with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [b_2_0: 2-Cocycle in H^*(A_8; GF(2)),
         c_4_1: 4-Cocycle in H^*(A_8; GF(2)),
         b_6_1: 6-Cocycle in H^*(A_8; GF(2)),
         b_6_2: 6-Cocycle in H^*(A_8; GF(2)),
         b_3_0: 3-Cocycle in H^*(A_8; GF(2)),
         b_3_1: 3-Cocycle in H^*(A_8; GF(2)),
         b_5_2: 5-Cocycle in H^*(A_8; GF(2)),
         b_7_5: 7-Cocycle in H^*(A_8; GF(2)),
         b_7_6: 7-Cocycle in H^*(A_8; GF(2))]
        Minimal list of algebraic relations:
        [b_3_0*b_3_1,
         b_3_0*b_5_2,
         b_2_0*b_7_5,
         b_2_0*b_7_6,
         b_6_1*b_3_0,
         b_6_2*b_3_0,
         b_3_0*b_7_5,
         b_3_0*b_7_6,
         b_3_1*b_7_5,
         b_3_1*b_7_6,
         b_5_2^2+b_2_0*b_3_1*b_5_2+b_2_0^2*b_6_2+c_4_1*b_3_1^2,
         b_6_1*b_6_2+b_6_1^2+b_2_0^2*b_3_1*b_5_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*c_4_1*b_6_2,
         b_5_2*b_7_5,
         b_5_2*b_7_6,
         b_6_1*b_7_6+b_6_1*b_7_5,
         b_6_2*b_7_5+b_6_1*b_7_5,
         b_7_5*b_7_6+b_7_5^2]
        sage: print(HA8_direct)
        Cohomology ring of AlternatingGroup(8) with coefficients in GF(2)
        <BLANKLINE>
        Computation complete
        Minimal list of generators:
        [b_2_0: 2-Cocycle in H^*(A8; GF(2)),
         c_4_1: 4-Cocycle in H^*(A8; GF(2)),
         b_6_3: 6-Cocycle in H^*(A8; GF(2)),
         b_6_5: 6-Cocycle in H^*(A8; GF(2)),
         b_3_0: 3-Cocycle in H^*(A8; GF(2)),
         b_3_1: 3-Cocycle in H^*(A8; GF(2)),
         b_5_1: 5-Cocycle in H^*(A8; GF(2)),
         b_7_5: 7-Cocycle in H^*(A8; GF(2)),
         b_7_6: 7-Cocycle in H^*(A8; GF(2))]
        Minimal list of algebraic relations:
        [b_3_0*b_3_1,
         b_3_1*b_5_1,
         b_2_0*b_7_5,
         b_2_0*b_7_6,
         b_6_3*b_3_1+b_2_0*c_4_1*b_3_1,
         b_6_5*b_3_1,
         b_3_0*b_7_5,
         b_3_0*b_7_6,
         b_3_1*b_7_5,
         b_3_1*b_7_6,
         b_5_1^2+b_2_0*b_3_0*b_5_1+b_2_0^2*b_6_5+c_4_1*b_3_0^2,
         b_3_0^4+b_6_5*b_3_0^2+b_6_3*b_6_5+b_6_3^2+b_2_0^2*b_3_0*b_5_1+b_2_0^3*b_6_5+c_4_1*b_3_0*b_5_1+b_2_0*c_4_1*b_3_0^2+b_2_0^2*c_4_1^2,
         b_5_1*b_7_5,
         b_5_1*b_7_6,
         b_6_3*b_7_6+b_6_3*b_7_5,
         b_6_5*b_7_5+b_6_3*b_7_5,
         b_7_5*b_7_6+b_7_5^2]

    But of course the two rings are isomorphic:

        sage: HA8.is_isomorphic(HA8_direct)
        ('1*b_2_0',
         '1*c_4_1',
         '1*b_3_0^2+1*b_6_3+1*b_2_0*c_4_1',
         '1*b_6_5',
         '1*b_3_1',
         '1*b_3_0',
         '1*b_5_1',
         '1*b_7_5',
         '1*b_7_6')

    The default way of computation is in fact more efficient, since less stability conditions are involved:

        sage: len(HA8._PtoPcapCPdirect)
        4
        sage: len(HA8.subgroup_cohomology()._PtoPcapCPdirect)
        1
        sage: len(HA8_direct._PtoPcapCPdirect)
        18

  `from_workspace`(*args, **kwds)

    Retrieve a cohomology ring from the workspace.

    NOTE:

    By default, the user’s current workspace is hosting the computation anyway. However, it is possible that the data is in fact copied from local sources outside of the workspace. This method temporarily disallows the use of other local or remote sources, so that it is guaranteed that only “fresh” data in the workspace are used.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: H = CohomologyRing.from_workspace(8,3)
        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:
        []

  `get_local_sources`()

    Return the location of the current local sources.

    EXAMPLE:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.reset()
        sage: try:
        ....:     from sage.env import SAGE_SHARE
        ....: except ImportError:
        ....:     try:
        ....:         from sage.misc.misc import SAGE_SHARE
        ....:     except ImportError:
        ....:         from sage.misc.misc import SAGE_DATA as SAGE_SHARE
        sage: CohomologyRing.get_local_sources().startswith(os.path.realpath(SAGE_SHARE))
        True
        sage: tmp = tmp_dir()
        sage: CohomologyRing.set_local_sources(tmp)
        sage: CohomologyRing.get_local_sources().startswith(os.path.realpath(tmp))
        True

  `get_workspace`()

    Return the location of the current workspace.

    EXAMPLE:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.reset()
        sage: CohomologyRing.get_workspace().startswith(os.path.realpath(DOT_SAGE))
        True
        sage: tmp = tmp_dir()
        sage: CohomologyRing.set_workspace(tmp)
        sage: CohomologyRing.get_workspace().startswith(os.path.realpath(tmp))
        True

  `global_options`(*args, **kwds)

    Set global options for cohomology computations.

    INPUT:

    - arbitrary strings, as positional arguments.

    - optional keyword arguments that provide values to be assigned to an option.

    There are the special string values “warn”, “info” and “debug”, that set the logging level accordingly, and moreover “walltime” (the walltime spent since setting this option will be added to the log), “cputime” (the cputime spent since setting this option will be added to the log), “time” (the log will include both walltime and cputime). With “notime”, “nowalltime” and “nocputime”, the corresponding logging option can be switched off.

    For any other string that does not start start with \("no"\), the option with that name is set to `True`. If it is of the form `"no"+X`, then the option with the name `X` is set to `False`. If there is no input, a copy of the dictionary of options is returned.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.reset()
        sage: sorted(CohomologyRing.global_options().items())
        [('NrCandidates', 1000),
         ('SingularCutoff', 70),
         ('autolift', 1),
         ('autoliftElAb', 0),
         ('reload', True),
         ('save', True),
         ('sparse', False),
         ('useMTX', True),
         ('use_web', True)]
        sage: CohomologyRing.global_options('sparse', 'nosave', autolift=4)
        sage: sorted(CohomologyRing.global_options().items())
        [('NrCandidates', 1000),
         ('SingularCutoff', 70),
         ('autolift', 4),
         ('autoliftElAb', 0),
         ('reload', True),
         ('save', False),
         ('sparse', True),
         ('useMTX', True),
         ('use_web', True)]
        sage: CohomologyRing.reset()

  `group_name`(G, GroupName=None)

    Determine a name for the given group.

    NOTE:

    This is just an auxiliary method and could as well be directly written in the code.

    INPUT:

    - `G` – a list, either comprised by two integers that form the address of a group in the SmallGroups library, or by a group in the libGAP interface.

    - `GroupName` – an optional string, a name provided by the user.

    If `GroupName` is provided, it will be used. Otherwise, if the group is given by its SmallGroup address, `None` is returned. Otherwise, if the group is provided with a custom name in GAP, it will be used. Otherwise, `None` is returned.

    NOTE:

    This package has a list of custom names for certain groups in the SmallGroups library. However, this list is only used in the initialisation of `COHO`.

    EXAMPLE:

        sage: from pGroupCohomology import CohomologyRing
        sage: G = libgap.eval('DihedralGroup(8)')
        sage: CohomologyRing.group_name((8,3))
        sage: CohomologyRing.group_name((8,3),'D8')
        'D8'
        sage: CohomologyRing.group_name([G],'D8')
        'D8'
        sage: CohomologyRing.group_name([G])
        sage: G.SetName("DihedralGroup_8")
        sage: CohomologyRing.group_name([G])
        'DihedralGroup_8'
        sage: CohomologyRing.group_name([G],'D8')
        'D8'

  `gstem`(G, GStem=None, GroupName=None, GroupId=None)

    Return a group identifier that is used to create file names.

    INPUT:

    - `G` – A list, either containing a single group in GAP or two integers providing an address in the SmallGroups library.

    - `GStem` – (optional string) if provided, it will be used.

    - `GroupName` – (optional string) if provided, if `G` contains a single group and no other optional arguments are provided, it is used.

    - `GroupId` – (optional pair of integers) If `G` contains a single group, `GroupId` is supposed to be its address in the SmallGroups library.

    OUTPUT:

    - A normalised version of `GStem`, if it is provided.

    - `<q>gp<n>`, if the SmallGroups address is provided by either `G` or `GroupId`.

    - A normalised version of `GroupName`, if it is provided.

    - If `G` contains a single group that has been given a custom name in GAP, a normalised version of this Name is returned.

    - Otherwise, an error is raised.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.gstem([8,3])
        '8gp3'
        sage: CohomologyRing.gstem([8,3],GStem='DihedralGroup(8)')
        'DihedralGroup_8_'
        sage: CohomologyRing.gstem([libgap.eval('DihedralGroup(8)')],GroupName='DG(8)')
        'DG_8_'
        sage: CohomologyRing.gstem([libgap.eval('DihedralGroup(8)')],GroupName='DG(8)',GroupId=[8,3])
        '8gp3'
        sage: G = libgap.eval('DihedralGroup(8)')
        sage: G.SetName("DG_8")
        sage: CohomologyRing.gstem([G])
        'DG_8'
        sage: CohomologyRing.gstem([libgap.eval('DihedralGroup(8)')])
        Traceback (most recent call last):
        ...
        ValueError: Cannot infer a short group identifier. Please provide one of the optional arguments ``GStem`` or ``GroupName``

  `reset`()

    Reset the cohomology ring machinery’s initial state.

    We mainly use this to avoid side effects of doctests affecting other doctest.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.reset()
        sage: sorted(CohomologyRing.global_options().items())
        [('NrCandidates', 1000),
         ('SingularCutoff', 70),
         ('autolift', 1),
         ('autoliftElAb', 0),
         ('reload', True),
         ('save', True),
         ('sparse', False),
         ('useMTX', True),
         ('use_web', True)]
        sage: CohomologyRing.global_options('sparse', 'nosave', autolift=4)
        sage: sorted(CohomologyRing.global_options().items())
        [('NrCandidates', 1000),
         ('SingularCutoff', 70),
         ('autolift', 4),
         ('autoliftElAb', 0),
         ('reload', True),
         ('save', False),
         ('sparse', True),
         ('useMTX', True),
         ('use_web', True)]
        sage: CohomologyRing.reset()
        sage: sorted(CohomologyRing.global_options().items())
        [('NrCandidates', 1000),
         ('SingularCutoff', 70),
         ('autolift', 1),
         ('autoliftElAb', 0),
         ('reload', True),
         ('save', True),
         ('sparse', False),
         ('useMTX', True),
         ('use_web', True)]

  `set_local_sources`(folder=True)

    Define which local sources to be used.

    INPUT:

    `folder` - (optional, default `True`) a bool or a string

    OUTPUT:

    - If `folder` is a non-empty string, it will be used as the root directory of local sources in subsequent cohomology computations.

    - If the user has write permissions in this folder, it is actually used to create rings. Otherwise, it is only used to read existing cohomology data, but all new computations will still be done in the user’s workspace.

    - If `folder` is `True` then the default location of the local sources is reset; this is a sub-directory of `SAGE_SHARE`.

    - If `bool(folder)` is `False` then the user’s workspace will be used to create new data in subsequent computations, even if the user has write permission for the local sources.

    EXAMPLES:

        sage: from pGroupCohomology import CohomologyRing
        sage: CohomologyRing.doctest_setup()       # reset, block web access, use temporary workspace
        sage: tmp_priv = tmp_dir()
        sage: tmp_publ = tmp_dir()
        sage: CohomologyRing.set_workspace(tmp_priv)

    If the local sources are set by the user to a location for which s/he has write permissions, then it is used for creating a cohomology ring:

        sage: CohomologyRing.set_local_sources(tmp_publ)
        sage: H1 = CohomologyRing(8,3)
        sage: H1.root.startswith(os.path.realpath(tmp_publ))
        True

    After unsetting it, the workspace is used instead:

        sage: CohomologyRing.set_local_sources(False)
        sage: H2 = CohomologyRing(8,3)
        sage: H2.root.startswith(os.path.realpath(tmp_priv))
        True

    `CohomologyRing.set_local_sources(False)` did not reset the default local sources (that by default are read-only); but `CohomologyRing.set_local_sources(True)` does:

        sage: CohomologyRing.set_local_sources(True)
        sage: from sage.env import SAGE_SHARE
        sage: CohomologyRing.get_local_sources().startswith(os.path.realpath(SAGE_SHARE))
        True

  `set_remote_sources`(URLs=None)

    Redefine the default locations of web repositories for cohomology rings

    INPUT:

    `URLs`, a tuple of strings providing a URLs, or `None`.

    If `URLs` is a tuple, then cohomology rings will be sought in the repositories denoted by the URLs (in the order given). In particular, if the tuple is empty, no web repositories will be used. If it is `None`, the locations are reset to some default.

    EXAMPLES:

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

    During package installation, internet access is impossible. Therefore, we simulate the use of a web repository by accessing local files that are available during package installation:

        sage: CohomologyRing.set_remote_sources(('file://'+os.path.join(os.path.realpath(os.path.curdir),'test_data'),))
        sage: H = CohomologyRing.from_remote_sources('8gp3')
        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]

  `set_workspace`(s=None)

    Define the location of the user’s workspace.

    INPUT:

    `s`, a string providing a folder name, or `None`.

    OUTPUT:

    If `s` is a string, a cohomology database in the folder `s` will be activated as the user’s workspace. Write permission for that folder is required. If it is `None`, a workspacee in a default location will be activated.

    NOTE:

    If necessary, the folder will be created as soon as data from `s` are requested.

    EXAMPLES:

        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: H = CohomologyRing(8,3)
        sage: H.root.startswith(os.path.realpath(tmp_root))
        True

`pGroupCohomology.factory.` `unit_test_64`(**kwds)

  Compare computation from scratch with data in the database.

  The cohomology rings for all groups of order 64 are computed from sratch and the results are compared with the data that are shipped with this package.

  NOTE:

  This test is likely to take between 30 and 60 minutes, depending on the computer.

  INPUT:

  - test_isomorphism (optional bool, default False): Whether to properly test for isomorphy (which may take a long time) instead of only testing for equality of generator degrees and of Poincaré series.

  - Optional keyword arguments for the creation of cohomology rings.

  OUTPUT:

  - A list of integers, giving the address of groups of order 64 in the Small Groups library for which a cohomology computation yields (with the given keyword arguments) a ring that is not isomorphic to the corresponding entry of the database. So, this list should be empty.

  - A list of three real numbers, giving the total computation time (wall time), the Python CPU-time and the Singular CPU-time, in seconds.

  During the computation, there is some information on the progress of the test.

  TEST:

      sage: from pGroupCohomology.factory import unit_test_64

  By default, i.e., without providing an explicit value `False` for `from_scratch`, the rings are computed from scratch, using a temporary directory created by the test function (it can be prescribed by providing an explicit value for `root`). This is a serious test and may involve some isomorphism tests, as different package versions or different options may very well result in different but isomorphic ring sturctures.

  Since doctests are supposed to be much shorter, we allow here to retrieve the data from the local sources (`from_scratch=False`). By consequence, the cohomology rings are simply reloaded and we merely test that pickling works.

      sage: L, t = unit_test_64(from_scratch=False)    # long time
      #  1: Walltime   ... min
            CPU-time   ... min
            Singular   ... min
      ...
      #267: Walltime   ... min
            CPU-time   ... min
            Singular   ... min
      sage: L
      []