Projective Resolutions¶
AUTHORS:
 Simon King <simon.king@unijena.de> (Cython code)
 David J. Green <david.green@unijena.de> (underlying Ccode)

class
pGroupCohomology.resolution.
G_ALG
¶ A wrapper for David Green’s Ctype for group algebras of finite \(p\)groups.
NOTE:
This extension class is internally used in
RESL
. Its purpose is simply to provide a couple of very basic methods around the underlying Ctype.The user is warned not to use this class independently!
When an instance of
G_ALG
is attribute of an instance ofRESL
, they share some Cdata. So, when deallocating them, it has to be taken care that the shared data are not freed twice (which would result in a segmentation fault). Our solution is that these Cdata are freed when theRESL
instance is deallocated, but are usually not freed if theG_ALG
instance is deallocated.Hence, if one would create a
G_ALG
instance independent from aRESL
instance, the Cdata would not be freed, resulting in a memory leak. Our solution for this second problem is to provide an optional argument ‘dependent’. If it isTrue
(which is default) then theG_ALG
instance behaves like being part of aRESL
instance, and the Cdata are not deallocated when the instance is deleted.In the following examples, we define
dependent=False
, and then the Cdata will be properly deallocated.An instance of
G_ALG
can be created using files that are created withmakeGroupData()
ormakeSpecialGroupData()
.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, G_ALG sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: G = G_ALG(gstem,folder=gps_folder,dependent=False) sage: G GF(2)[8gp3]

coef
()¶ Return the characteristic of the base field.
EXAMPLES:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, G_ALG sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: G = G_ALG(gstem,folder=gps_folder,dependent=False) sage: G.coef() 2

kG_map
(M, x)¶ Image of an element of a right \(\mathbb F_pG\)module under a \(\mathbb F_pG\)module morphism.
INPUT:
 M – \(((s\cdot r) \times G)\)
Matrix_gfpn_dense
matrix, representing a right\(\mathbb F_pG\)module morphism from a free right \(\mathbb F_pG\)module of rank \(r\) to a free right \(\mathbb F_pG\)module of rank \(s\), where \(G\) is a finite \(p\)group. The data ofM
are organized in \(s\) blocks of \(r\) rows.  x – \((r \times G)\)
Matrix_gfpn_dense
matrix representing an element of a free right \(\mathbb F_pG\)module of rank \(r\)
OUTPUT:
A \((s \times G)\)
Matrix_gfpn_dense
matrix representing the image ofx
under the map represented byM
EXAMPLES:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, G_ALG sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: G = G_ALG(gstem,folder=gps_folder,dependent=False) sage: M = MTX(MatrixSpace(GF(2),4,8, implementation=MTX), [[1,0,0,0,0,0,0,0],[0,1,0,1,0,1,0,1],[1,0,0,0,0,0,0,0],[1,0,1,0,1,0,1,0]]) sage: G.kG_map(M,MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,0,1,0,1,0,1,0],[0,1,0,1,0,1,0,1]])) [1 1 1 1 1 1 1 1] [0 0 0 1 1 1 1 0] sage: G.kG_map(M,MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[0,1,0,1,0,1,0,1],[1,0,1,0,1,0,1,0]])) [1 1 1 1 1 1 1 1] [1 0 0 0 0 1 1 0]
The image of the sum is the sum of the images:
sage: G.kG_map(M, MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[1,1,1,1,1,1,1,1],[1,1,1,1,1,1,1,1]])) [0 0 0 0 0 0 0 0] [1 0 0 1 1 0 0 0]
 M – \(((s\cdot r) \times G)\)

l_action
(M)¶ Return matrix for left action on \(kG\) by the element represented by a vector.
INPUT:
M – a
Matrix_gfpn_dense
matrix with a single row and \(G\) columns, representing an element of the group algebra of a finite \(p\)group \(G\)OUTPUT:
A \(G\times G\)
Matrix_gfpn_dense
matrix describing the left action of the given element on the group algebra. The result of the left action is obtained by matrix multiplication from the right side.EXAMPLES:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, G_ALG sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: G = G_ALG(gstem,folder=gps_folder,dependent=False) sage: G.l_action(MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[1,0,0,1,0,1,1,0]])) [1 0 0 1 0 1 1 0] [0 1 0 0 0 1 0 1] [0 0 1 0 0 0 0 1] [0 0 0 1 0 0 0 1] [0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1] sage: MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,0,0,0,0]])*G.l_action(MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,1,0,0,0]])) [0 0 0 1 1 0 1 0] sage: G.kG_map(MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,1,0,0,0]]),MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,0,0,0,0]])) [0 0 0 1 1 0 1 0]

order
()¶ Return order of the group.
EXAMPLES:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, G_ALG sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: G = G_ALG(gstem,folder=gps_folder,dependent=False) sage: G.order() 8

r_action
(M)¶ Return matrix for right action on kG by the element represented by a vector.
INPUT:
M – a
Matrix_gfpn_dense
matrix with a single row and \(G\) columns, representing an element of the group algebra of a finite \(p\)group \(G\)OUTPUT:
A \(G\times G\)
Matrix_gfpn_dense
matrix describing the right action of the given element on the group algebra. The result of the action is obtained by matrix multiplication from the right side.EXAMPLES:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, G_ALG sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: G = G_ALG(gstem,folder=gps_folder,dependent=False) sage: print(G.r_action(MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[1,0,0,1,0,1,1,0]]))) [1 0 0 1 0 1 1 0] [0 1 0 0 0 0 0 1] [0 0 1 0 0 0 1 1] [0 0 0 1 0 0 0 1] [0 0 0 0 1 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1] sage: MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,0,0,0,0]])*G.r_action(MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,1,0,0,0]])) [0 0 0 1 1 1 0 0] sage: G.kG_map(MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,0,0,0,0]]), MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,1,0,0,0]])) [0 0 0 1 1 1 0 0]


class
pGroupCohomology.resolution.
LIFTcontainer
¶ An extension class whose purpose is to cache the lifts of chain maps of a resolution to itself.
A typical use case is the computation of cohomology rings. One frequently has to compute cup products of \(m\) and \(n\)cochains. To that purpose, the cochains are transformed into chain maps of degree \(m\) and \(n\). Then, the two chain maps are composed, and the result is transformed into a \((m+n)\)cochain. For computing the composition, the \(m\)th lift of the second chain map needs to be known.
Now, if many cup products have to be computed, it is reasonable to cache previously computed lifts.
NOTE:
Internally, any
RESL
instance has a member that is aLIFTcontainer
instance, and if the cup product of cochains is computed (seeCOCH
for more details), caching is automatically done.EXAMPLE:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, LIFTcontainer sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: L = LIFTcontainer(R) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]], mutable=False) sage: C3 = R.liftChainMap(R.CochainToChainmap(2,C)) sage: C3 ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] 3, 1, [1 0 0 0 0 0 0 0] ) sage: L[3,2,C] = C3[2] sage: L.out() {(3, 2): {[1 0 1]: [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [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 0 0 0 0] [1 0 0 0 0 0 0 0]}} sage: L[3,2,C] [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]

export
()¶ Store cached lifts on disk. The file names are determined by the parent of
self
.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, LIFTcontainer sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: L = LIFTcontainer(R) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]], mutable=False) sage: C3 = R.liftChainMap(R.CochainToChainmap(2,C)) sage: C3 ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] 3, 1, [1 0 0 0 0 0 0 0] ) sage: L[3,2,C] = C3[2] sage: L.out() {(3, 2): {[1 0 1]: [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [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 0 0 0 0] [1 0 0 0 0 0 0 0]}} sage: L.export() sage: L.out() {(3, 2): {'file': '.../8gp3/dat/L8gp3n3d2'}}
Here are the saved contents:
sage: E = load(L.out()[(3,2)]['file']) sage: E [( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 1], [1 0 0 0 0 0 0 0] )] sage: E[0][0] == C True sage: E[0][1] == C3[2] True

out
()¶ Return the dictionary of cached lifts.
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, LIFTcontainer sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: L = LIFTcontainer(R) sage: L.out() {}
In principle, any data can be stored in a LIFTcontainer.
sage: L[1,2,3] = 4 sage: L.out() {(1, 2): {3: 4}}

parent
()¶ Return the resolution for which
self
was defined.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, LIFTcontainer sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: L = LIFTcontainer(R) sage: R is L.parent() True


class
pGroupCohomology.resolution.
MasseyDefiningSystems
(all=True, *L)¶ A tool for computing defining systems for Massey products.
NOTE:
This class is used behind the scenes in
massey_products()
.INPUT:
Y_1,Y_2,...
: Yoneda cochains (YCOCH
) over a common resolutionThe method
value()
returns a list of all possible values (given by Yoneda cochains) for defining systems of the Massey products ofY_1,Y2,...
.EXAMPLES:
sage: from pGroupCohomology import CohomologyRing sage: from pGroupCohomology.resolution import MasseyDefiningSystems sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3) sage: H.make() sage: H.rels() ['b_1_0*b_1_1']
Since the product of the two degree one generators of
H
vanish, it makes sense to compute Massey products:sage: Y1 = H.2.yoneda_cocycle() sage: Y2 = H.3.yoneda_cocycle() sage: M = MasseyDefiningSystems(Y1,Y2,Y1) sage: P = M.values() sage: len(P) 16 sage: print(P[0][0]) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] sage: print(P[0][1]) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] sage: print(P[1][0]) [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] sage: print(P[1][1]) [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 1 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0]
Hence, there are both trivial and nontrivial cocycles in the Massey product of
H.2
,H.3
,H.2
.
values
()¶ Return all possible values (Yoneda cochains) of defining systems of Massey products.
EXAMPLES:
We use an example with a noncommutative cohomology ring.:
sage: from pGroupCohomology import CohomologyRing sage: from pGroupCohomology.resolution import MasseyDefiningSystems sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(9,2) sage: H.make() sage: H.3 a_1_0: 1Cocycle in H^*(SmallGroup(9,2); GF(3)) sage: Y = H.3.yoneda_cocycle() sage: M = MasseyDefiningSystems(Y,Y,Y) sage: P = M.values() sage: len(P) 81 sage: print(P[0][0]) [0 0 0 0 0 0 0 0 0] [2 0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0] sage: print(P[1][0]) [0 0 0 0 0 0 0 0 0] [2 1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0] sage: print(P[2][0]) [0 0 0 0 0 0 0 0 0] [2 2 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0 0]
Hence, in this case, the Massey product only contains different nontrivial cocycles.


class
pGroupCohomology.resolution.
RESL
¶ Computating minimal projective resolutions for finite \(p\)groups with coefficients in
GF(p)
.INPUT:
gstem
– a string, providing a short unique descriptor of a finite \(p\)group (seemakeSpecialGroupData()
)gps_folder
(optional) – a string, defining the folder in which data for the group specified bygstem
can be found. Default:gps_folder=''
res_folder
(optional) – a string, defining the folder in which the data for the resolution will be stored. Default:res_folder=''
NOTE:
 Usually, one wouldn’t create an instance of RESL on its own. The normal
usage is to create a cohomology ring by
CohomologyRing()
, which internally will produce an instance of RESL.
OUTPUT:
A resolution, which is given by data files in
res_folder
, where the file names start with'Res'+gstem
.EXAMPLES:
Usually, objects of type RESL will only play a role when computing a cohomology ring. But as such, they are hardly visible, and will hardly ever be directly used. Nevertheless, we hope that the following examples give some insight on how the RESL class works.
Creating a RESL object
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, coho_logger sage: makeGroupData(8,3,folder=tmp_root)
The
gstem
is'8gp3'
, so, the group data are stored in the folderos.path.join(tmp_root,'8gp3')
, to which we refer as the stem folder. The functionmakeGroupData()
also creates a subdirectory'dat'
of the stem folder, which is intended to be used for storing the resolution.sage: gstem='8gp3' sage: gps_folder = os.path.join(tmp_root,gstem) sage: res_folder = os.path.join(gps_folder, 'dat') sage: R = RESL(gstem,gps_folder,res_folder) sage: R Resolution of GF(2)[8gp3] sage: print(R) Resolution: 0 < GF(2) < GF(2)[8gp3]
So far, only term number zero of the resolution was created. We compute up to term number four, logging the computation:
sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.global_options('info') sage: R.nextDiff() sage: R.nextDiff() Resolution of GF(2)[8gp3]: Computing next term > rk P_02 = 3 sage: R.nextDiff() Computing next term > rk P_03 = 4 sage: R.nextDiff() Computing next term > rk P_04 = 5
nextDiff()
writes data into the fileres_folder
. By default, if data from previous computations are present, they will be automatically reloaded. This can be switched off by unsetting the option'reload'
. We illustrate reloading here, by redefiningR
:sage: R = RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() Resolution of GF(2)[8gp3]: Differential reloaded > rk P_02 = 3 sage: R.nextDiff() Differential reloaded > rk P_03 = 4 sage: R.nextDiff() Differential reloaded > rk P_04 = 5 sage: print(R) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2 < rank 3 < rank 4 < rank 5
There is a copy method for resolutions, and it is also possible to save and load RESL objects:
sage: S = copy(R) sage: print(S) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2 < rank 3 < rank 4 < rank 5 sage: S = loads(dumps(R)) Resolution of GF(2)[8gp3]: Differential reloaded > rk P_02 = 3 Differential reloaded > rk P_03 = 4 Differential reloaded > rk P_04 = 5 sage: print(S) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2 < rank 3 < rank 4 < rank 5
However,
R
and its copyS
are not fully independent, as they share the same files on the disk. Moreover, when savingR
into a file ‘file.sobj’ then ‘file.sobj’ would not contain the data provided by the files inres_folder
; instead, it contains pointers to these data files. Therefore, moving ‘file.sobj’ to a different platform does not suffice to reconstruct the resolution. Ifres_folder
andgps_folder
are absolute path names, then even moving the whole root folder to another location would not allow for reloading the resolution, since the paths break.See
pGroupCohomology
for a discussion of that problem. However, the problem is rather easy to work around forRESL
: All data files used and produced byRESL
have a unique location relative togps_folder
andres_folder
. And all methods producing the data files would also be able to reload the data from the files. So, a reconstruction of theRESL
object is easy provided the option ‘reload’ is used, and moving the folders thus is possible:sage: tmp_root2 = tmp_dir() sage: new_gps_folder = os.path.join(tmp_root2,gstem) sage: new_res_folder = os.path.join(new_gps_folder,'dat') sage: import os sage: os.rename(tmp_root,tmp_root2) sage: S = RESL(gstem,new_gps_folder,new_res_folder) sage: S.nextDiff() sage: S.nextDiff() Resolution of GF(2)[8gp3]: Differential reloaded > rk P_02 = 3 sage: CohomologyRing.global_options('warn') sage: del S sage: os.rename(tmp_root2,tmp_root)
Differentials
A
RESL
object represents a minimal free resolution for a finite \(p\)group \(G\), hence, it provides a sequence of free \(\mathbb F_p\)modules that are related by homomorphisms, the differentials. The construction of the resolution relies on Cprograms developped by David Green. They involve a certain noncommutative Groebner basis theory due to David Green.A homomorphism from a rank \(r\) to a rank \(s\) free \(\mathbb F_p\)module can be described by a \(r\times s\) matrix with coefficients in \(\mathbb F_p\). An element of \(\mathbb F_pG\) can be represented by a tuple of length \(G\) of elements of \(\mathbb F_p\). Therefore, the data for the differentials are stored as matrices with \(G\) columns and \(r\times s\) rows. Since David Green’s programs use CMeatAxe for linear algebra over finite fields, our
RESL
class relies on our CMeatAxe wrapperMatrix_gfpn_dense
.If sufficiently many terms of the resolution are computed (using
nextDiff()
), the differentials can be easily requested:sage: print(R) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2 < rank 3 < rank 4 < rank 5 sage: R[2] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 1 0 0]
So, indeed the matrix has the right dimension: The group is of order 8, and the first and second term of the resolution are of rank 2 and 3, respectively:
sage: R.rank(1) 2 sage: R.rank(2) 3
Blocks of \(s=2\) rows of the matrix correspond to elements in the image of the differential:
sage: R[2][0:2] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] sage: R[2][2:4] [0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] sage: R[2][4:6] [0 0 0 0 0 0 1 0] [0 0 0 0 0 1 0 0]
These blocks encode a cochain, hence, a map from some term of the resolution (here: a term of rank two, corresponding to the number of rows) to the group algebra (whose elements are encoded by a \(1\times G\) matrix.
The salient feature of a resolution is that the composition of two differentials is zero. This can be verified as follows (where we use
get_slice()
, sinceR[2][0:2]
would return a matrix relying on a different implementation):sage: R.applyDiff(1,R[2].get_slice(0,2)) [0 0 0 0 0 0 0 0] sage: R.applyDiff(1,R[2].get_slice(2,4)) [0 0 0 0 0 0 0 0] sage: R.applyDiff(1,R[2].get_slice(4,6)) [0 0 0 0 0 0 0 0]
Cochains and chain maps
A \(d\)cochain \(c\) is a \(\mathbb F_pG\)module morphism from the \(d\)th term of the resolution to \(\mathbb F_p\).
Embedding \(\mathbb F_p=\mathbb F_p\cdot 1 \subset \mathbb F_pG\), we obtain a map to the 0th term of the resolution. This gives rise to a chain map of degree \(d\), hence, a collection of a map from the \((n+d)\)th term \(R_{n+d}\) to the \(n\)th term \(R_n\) of the resolution, for all \(n\ge 0\), that commute with the differentials.
It is iteratively constructed as follows. Let the map \(c_n: R_{n+d}\to R_n\) be already known. We compose the differential \(\partial_{n+1+d}\) with it and obtain a map \(\partial_{n+1+d}\circ c_n: R_{n+1+d}\to R_n\). It is easy to show that its image is contained in the image of \(\partial_{d+1}\). We choose one of the preimages, and obtain the next term \(c_{n+1}: R_{n+1+d}\to R_{n+1}\). We refer to that construction as ‘lifting’.
Here is a stepbystep example. Note that
COCH
provides this functionality with highlevel functions, hence, it is not needed to perform the following steps manually.First, we define a \(1\times 3\) matrix that represents a 2cochain, and construct the lowest term of the corresponding chain map:
sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX),[[1,0,1]]) sage: c0 = R.CochainToChainmap(2,C) sage: c0 ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 2, 0, [1 0 0 0 0 0 0 0] )
In the next section, we discuss two differnt ways to lift the cochain. Here is the result:
sage: c1 = R.liftChainMap(c0) sage: c1 ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] 3, 1, [1 0 0 0 0 0 0 0] )
We verify whether the result is correct. So, we first compose the third differential with
c0
:sage: d3c0 = R.composeChainMaps(R[3],c0[2],3,2,0) sage: d3c0 [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 1 0 0 0 0 1 0] [0 0 1 0 0 0 0 0]
The matrix defining c1 contains 4 blocks of 2 rows, and we verify that their images under the first differential coincide with the rows of
d3c0
:sage: d3c0.get_slice(0,1) == R.applyDiff(1,c1[2].get_slice(0,2)) True sage: d3c0.get_slice(1,2) == R.applyDiff(1,c1[2].get_slice(2,4)) True sage: d3c0.get_slice(2,3) == R.applyDiff(1,c1[2].get_slice(4,6)) True sage: d3c0.get_slice(3,4) == R.applyDiff(1,c1[2].get_slice(6,8)) True
So, associated with the cochain
C
we obtain a chain mapc
. For obtaining the cup product ofC
with itself, we composec
with itself. We obtain a chain map of degree \(4\), and its lowest term, composed with the augmentation map \(\mathbb F_pG\to \mathbb F_p\) yields the cochainC*C
. But first, we have to liftc
one step further:sage: c2 = R.liftChainMap(c1)
This can be composed with
c0
:sage: cc = R.composeChainMaps(c2[2],c0[2],4,2,0) sage: cc [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]
The basis of \(\mathbb F_pG\) is chosen so that the kernel of the augmentation map is given by all columns after the first. Hence, the cup product of
C
with itself is given by[1,0,0,0,1]
.Using the class
COCH
, the computation is of course much more comfortable. For using this class, we need to create a cohomology ring, since we consider cochains as (representatives of) cohomology classes:sage: from pGroupCohomology.cochain import COCH sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: CohomologyRing.set_workspace(tmp_root) sage: H = CohomologyRing(8,3, from_scratch=True) sage: C = COCH(H,2,'C',[1,0,1]) sage: C*C (C)*(C): 4Cocycle in H^*(D8; GF(2)) sage: print(C*C) 4Cocycle in H^*(D8; GF(2)), represented by [1 0 0 0 1]
Urbild Groebner bases and autolift
We have seen in the previous section that for dealing with chain maps and for computing cup products one has to determine preimages of differentials. In cohomology computations, these operations occur extremely often, so, it is essential to make them fast.
When successively computing the terms of a resolutions, David Green’s programs construct socalled Urbild Groebner bases and stores them in files in the directory
res_folder
(as provided in the definition ofR
). They can also be used to lift chain maps. Usingc1
from above, we get:sage: CohomologyRing.global_options('info') sage: c2U = R.liftChainMap(c1)
However, that method is rather slow. It is also possible to use some linear algebra to pick an element of the preimage, but this requires to construct certain data first:
sage: R.makeAutolift(2) Resolution of GF(2)[8gp3]: Make degree 2 autolift data sage: c2A = R.liftChainMap(c1)
It takes some time to make the autolift data, but if they are present, the lifting is much faster. Hence, if possible they are used. If one wants to use the Urbild Groebner bases, this can still be done with
ugb_liftChainMap()
, although this has a slightly different syntax. The autolift method used to be more than 250 times faster than the Urbild Groebner basis method, but optimisations in recent package versions made the running time almost equal on some machines, while on other machines there still is a factor of about 10:sage: CohomologyRing.global_options('warn') sage: timeit.eval('cX = R.liftChainMap(c1)') # random 625 loops, best of 3: 230 µs per loop sage: timeit.eval('cX = R.ugb_liftChainMap(c1[0]+1,c1[1]+1,c1[2])') # random 625 loops, best of 3: 297 µs per loop
In general, the lifts obtained with both methods are not the same (they may vary up to elements in the radical, hence, in the kernel of the augmentation map), but here they are the same:
sage: R.liftChainMap(c1)[2]==R.ugb_liftChainMap(c1[0]+1,c1[1]+1,c1[2]) True
Note that the construction of the autolift data in a certain degree only pays off if there will be many lifts to that degree. Hence, when computing a cohomology ring, we use the autolift method by default only up to degree 4.
But there is also another problem: The memory consumption. For some more complicated groups, the Urbild Groebner bases are huge in higher degrees, and the autolift data would even be worse. Therefore, if the nondefault option
'sparse'
is used, certain other data will be temporarily saved on disk before loading the Urbild Groebner bases, and vice versa.See
COHO
for examples.
ChainmapToCochain
(X)¶ Represent a chain map of degree \(n\) by a \(n\)cochain.
INPUT:
(n,0,M)
–M
is a \(\operatorname{rank}(P_n) \times G\)Matrix_gfpn_dense
matrix, where \(P_n\) is the \(n\)th term of self and \(G\) is the finite \(p\)group under consideration.OUTPUT:
A \(1 \times G\)
Matrix_gfpn_dense
matrix representing a \(n\)cochain.NOTE:
By our choice of bases of modules over the group algebra, the result only depends on the first column of
M
.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]]) sage: print(R.ChainmapToCochain(R.CochainToChainmap(2,C))) [1 0 1]

CochainToChainmap
(*args, **kwds)¶ RESL.CochainToChainmap(self, long n, Matrix_gfpn_dense Coc) > tuple
Represent a cochain (given by a matrix) by a chain map to the zeroeth term of
self
INPUT:  n – an integer  C – a
Matrix_gfpn_dense
matrix with only one row, representing a \(n\)cochainOUTPUT:
(n,0,M)
, where theMatrix_gfpn_dense
matrixM
represents the lowest term of a chain map of degree \(n\).NOTE:
By our choice of basis for modules over the group algebra, the matrix
M
is zero except in the first column, which is given by the transpose ofC
.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]]) sage: c = R.CochainToChainmap(2,C) sage: c ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 2, 0, [1 0 0 0 0 0 0 0] )

DiffList
()¶ Return the list of computed differentials of a resolution, respectively the path to saved data.
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.global_options('sparse') sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff()
Since in our test we use the nondefault option ‘sparse’, most of the differentials are not kept in memory but saved on disk, and
R.difflist()
points to their location:sage: R.DiffList() [ [0 1 0 0 0 0 0 0] [0 0 1 0 0 0 0 0], '.../8gp3/dat/Res8gp3d02.bin', '.../8gp3/dat/Res8gp3d03.bin' ]

G_ALG
()¶ Return the
G_ALG
object over which the resolution is defined.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.G_ALG() GF(2)[8gp3]

applyDiff
(n, x)¶ Apply \(n\)th differential map to an element \(x\) of the \(n\)th term of
self
.INPUT:
 n – integer, determining a term of self
 x – \((r \times G)\)
Matrix_gfpn_dense
matrix, where \(r\) is the projective rank of the \(n\)th term of self, and \(G\) is the group upon which \(R\) is defined.
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: R.rank(2) 3 sage: R.rank(3) 4
We will verify that the composition of the third differential with the second differential vanishes. Since the rank of the second term of the resolution is 3, the four blocks of 3 rows of the matrix R[3] correspond to generators of the image of the differntial:
sage: R.applyDiff(2,R[3].get_slice(0,3)) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] sage: R.applyDiff(2,R[3].get_slice(3,6)) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] sage: R.applyDiff(2,R[3].get_slice(6,9)) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] sage: R.applyDiff(2,R[3].get_slice(9,12)) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0]

coef
()¶ Return the characteristic of the field over which
self
is defined.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.coef() 2

composeChainMaps
(M1, M2, s, r, q)¶ Compose chain maps \(M1: P_s \to P_r\) with \(M2: P_r\to P_q\), where \(P\) is
self
.INPUT:
M1
,M2
–Matrix_gfpn_dense
matrices defining morphisms from the \(s\)th to the \(r\)th respectively from the \(r\)th to the \(q\)th term of selfs, r, q
– integers, refering to terms of self
OUTPUT:
A
Matrix_gfpn_dense
matrix representing the composition ofM1
withM2
, a chain map from the sth to the qth term of self.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff()
We verify that the composition of two differentials vanishes:
sage: print(R.composeChainMaps(R[2],R[1],2,1,0)) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] sage: print(R.composeChainMaps(R[3],R[2],3,2,1)) [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0]

composeListOfMaps
(M1, s, L2)¶ Compose one chain map with a list of chain maps.
INPUT:
M1
–Matrix_gfpn_dense
matrix defining a morphism from the \(s\)th to the \(r\)th term of selfs
– an integer, referring to a term of selfL
– a list/tuple whose elements are triples(r, q_i, M_i)
, whereM_i
is aMatrix_gfpn_dense
matrix describing a morphism from the \(r\)th to the \(q_i\)th term of self
OUTPUT:
A list of triples
[s,q_i,N_i]
, whereN_i
is aMatrix_gfpn_dense
matrix representing a morphism from the \(s\)th to the \(q_i\)th term of self, namely the composition ofM
withM_i
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]]) sage: c = R.CochainToChainmap(2,C) sage: c ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 2, 0, [1 0 0 0 0 0 0 0] ) sage: L = [(2,1,R[2]), c] sage: Comp = R.composeListOfMaps(R[3],3,L) sage: R.composeChainMaps(R[3],L[0][2],3,2,1) == Comp[0][2] True sage: R.composeChainMaps(R[3],c[2],3,2,0) == Comp[1][2] True

deg
()¶ Return the number of terms of self that have been computed so far.
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: R.deg() 3

exportAction
()¶ Internally used: Save list of \(G\)action matrices in a file.
EXAMPLE:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, coho_logger sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.exportAction() sage: load(os.path.join(res_folder,'A8gp3')) [ [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 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 1] [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 0 0 0 0 0 1], [0 0 0 0 0 0 0 0], [0 0 0 0 0 0 0 0], <BLANKLINE> [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] [0 0 0 0 0 1 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0], [0 0 0 0 0 0 0 0], [0 0 0 0 0 0 0 0], <BLANKLINE> [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 1] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0], [0 0 0 0 0 0 0 0] ]
The Gaction matrices are used to compute the autolift data, and only there. Hence, the action matrices will be imported if the autolift data are computed, and exported if this is finished:
sage: R.nextDiff() sage: R.nextDiff() sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.global_options('info') sage: R.makeAutolift(2) Resolution of GF(2)[8gp3]: Make degree 2 autolift data

exportLifts
()¶ Save cached lifts into files.
EXAMPLE:
sage: from pGroupCohomology import CohomologyRing sage: from pGroupCohomology.cochain import COCH sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3, from_scratch=True, options='sparse') sage: C = COCH(H,1,'C',[0,1]) sage: print(C*C) 2Cocycle in H^*(D8; GF(2)), represented by [0 1 0] sage: R = H.resolution()
Since we use the nondefault
sparse
option, some of the data is stored in a file:sage: sorted(R.getLifts().items()) [((1, 1), {'file': '.../8gp3/dat/L8gp3n1d1'}), ((2, 1), {[0 1]: (( [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0] 2, 1, [0 0 0 0 0 0 0 0] ), 2)})] sage: R.exportLifts()
Now, both lifts are stored on disk:
sage: sorted(R.getLifts().items()) [((1, 1), {'file': '.../8gp3/dat/L8gp3n1d1'}), ((2, 1), {'file': '.../8gp3/dat/L8gp3n2d1'})]

find_bounding_chain
(n, M, check=False)¶ Find a chain that yields a given \(n1\) chain under the \(n\)th differential.
INPUT:
n
– integer, determining a term of selfM
– \((r \times G)\)Matrix_gfpn_dense
matrix, where \(r\) is the projective rank of the \((n1)\)th term of self, and \(G\) is the group upon which \(R\) is defined.M
represents a chain.check
(optional bool) – ifTrue
, verify whether the input is in the kernel of the \((n1)\)th boundary map.
OUTPUT:
A \(n\)chain, represented by a \((s \times G)\)
Matrix_gfpn_dense
matrix, where \(s\) is the projective rank of the \(n\)th term of self.EXAMPLES:
sage: from pGroupCohomology import CohomologyRing sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3) sage: H.make() sage: R = H.resolution() sage: M1 = R.find_bounding_chain(1, MTX(MatrixSpace(GF(2),1,8, implementation=MTX), [[0,1,1,0,1,1,0,1]])) sage: print(M1) [1 0 0 0 1 0 0 0] [1 1 0 0 0 1 0 0] sage: print(R.applyDiff(1,M1)) [0 1 1 0 1 1 0 1] sage: M2 = R.find_bounding_chain(2, MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[0,1,0,1,0,0,1,0],[0,0,0,0,0,1,0,0]])) sage: print(M2) [1 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] sage: print(R.applyDiff(2,M2)) [0 1 0 1 0 0 1 0] [0 0 0 0 0 1 0 0]
Note that by default it is not verified whether the input is in the image of the \(n\)th boundary map. In this case, the output would be nonsense. So, in case of doubt, one may use the optional parameter
check
:sage: FOO = R.find_bounding_chain(2, MTX(MatrixSpace(GF(2), 2,8, implementation=MTX), [[0,1,0,1,0,0,1,0],[0,1,1,0,0,1,0,0]])) sage: print(FOO) [1 0 1 0 0 0 0 0] [1 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] sage: print(R.applyDiff(2,FOO)) [0 1 0 1 0 0 1 0] [0 0 1 0 0 1 0 0] sage: print(R.find_bounding_chain(2, MTX(MatrixSpace(GF(2),2,8, implementation=MTX), [[0,1,0,1,0,0,1,0],[0,1,1,0,0,1,0,0]]), check=True)) Traceback (most recent call last): ... ValueError: The given chain is no cycle

firstDiff
()¶ Make first differential for
self
.This function is usually called from nextDiff().
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.reset() sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.firstDiff() sage: print(R) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2
An error is raised if it is attempted to compute the first term again.
sage: R.firstDiff() Traceback (most recent call last): ... IndexError: First differential is already computed

free_ugb
()¶ Deallocate the currently loaded Urbild Groebner basis.
EXAMPLE:
sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: from pGroupCohomology.cochain import COCH sage: H = CohomologyRing(8,3, from_scratch=True) sage: R = H.resolution() sage: R.nextDiff() sage: R.nextDiff() sage: CohomologyRing.global_options('debug','nosparse') sage: C = COCH(H,1,'C',[1,0]) sage: D = C*C Resolution of GF(2)[D8]: Compute C*C Compose chain maps R_2 > R_1 > R_0 Lift with Urbild Groebner basis in degree 1 load Urbild Groebner basis
Now, the Urbild Groebner basis is allocated. Since we use the option
'nosparse'
, it is not automatically deallocated, and is used to lift further cochains:sage: C = COCH(H,1,'C',[0,1]) sage: D = C*C Compute C*C Compose chain maps R_2 > R_1 > R_0 Lift with Urbild Groebner basis in degree 1
Now we deallocate it manually. In the subsequent computation, it is reloaded again:
sage: R.free_ugb() deallocate Urbild Groebner basis sage: C = COCH(H,1,'C',[1,1]) sage: D = C*C Compute C*C Compose chain maps R_2 > R_1 > R_0 Lift with Urbild Groebner basis in degree 1 load Urbild Groebner basis

getLifts
()¶ Return the dictionary of cached lifts.
NOTE:
That function was only created in order to provide a doc test for
setLift()
.EXAMPLE:
sage: from pGroupCohomology import CohomologyRing sage: from pGroupCohomology.cochain import COCH sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3, from_scratch=True, options='sparse') sage: R = H.resolution() sage: R.nextDiff() sage: R.nextDiff() sage: C = COCH(H,1,'C',[0,1]) sage: R.getLifts() {} sage: print(C*C) 2Cocycle in H^*(D8; GF(2)), represented by [0 1 0]
Now, two lifts of
C
(considered as a chain map of degree one) are cached. If thesparse
option is used (which we do here, although it is currently not the default), one of the lifts is exported to a file in order to save memory:sage: sorted(R.getLifts().items()) [((1, 1), {'file': '.../8gp3/dat/L8gp3n1d1'}), ((2, 1), {[0 1]: (( [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0] 2, 1, [0 0 0 0 0 0 0 0] ), 2)})]

grouporder
()¶ Return the order of the group over wich
self
is defined.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.grouporder() 8

importAction
()¶ Reload list of \(G\)action matrices that have been exported using
exportAction()
.EXAMPLE:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL, coho_logger sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.reset() sage: CohomologyRing.global_options('sparse') sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.exportAction() sage: R.nextDiff() sage: R.nextDiff()
In the documentation of
exportAction()
, it is shown that usually the action matrices are imported bymakeAutolift()
. But it is alright to do it manually; it can be seen in the log that the matrices will not be imported twice (and note that the action is to be imported only since we use the nondefaultsparse
option):sage: CohomologyRing.global_options('debug') sage: R.importAction() Resolution of GF(2)[8gp3]: > import action matrices sage: R.makeAutolift(2) Make degree 2 autolift data

label
()¶ Return a short descriptor of this resolution.
EXAMPLES:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.label() 'Res8gp3'

liftChainMap
(X)¶ Lift Chain Map.
INPUT:
(n,d,M)
– aMatrix_gfpn_dense
matrixM
representing a morphism from the \(n\)th to the \(d\)th term of self, with \(d<n\).OUTPUT:
(n+1,d+1,N)
– AMatrix_gfpn_dense
matrixN
representing the lift ofM
to a morphism from the \((n+1)\)th to the \((d+1)\)th term of self.NOTE:
Uses the autolift method, if possible. See
RESL
for an explanation of the notion ‘lift’ and of the autolift method.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]]) sage: c = R.CochainToChainmap(2,C) sage: c ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 2, 0, [1 0 0 0 0 0 0 0] ) sage: cLift = R.liftChainMap(c) sage: cLift ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] 3, 1, [1 0 0 0 0 0 0 0] )

load_ugb
(d)¶ Load Urbild Groebner basis for lifts from degree \(d1\) to \(d\).
EXAMPLE:
sage: from pGroupCohomology import CohomologyRing sage: from pGroupCohomology.cochain import COCH sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3, from_scratch=True) sage: R = H.resolution() sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: CohomologyRing.global_options('debug','nosparse') sage: C = COCH(H,1,'C',[0,1]) Now, we load the Urbild Groebner basis for lifts to degree 1. Hence, it is not needed to load it again in the subsequent computation. :: sage: R.load_ugb(1) Resolution of GF(2)[D8]: load Urbild Groebner basis sage: D = C*C Compute C*C Compose chain maps R_2 > R_1 > R_0 Lift with Urbild Groebner basis in degree 1 But if we load the Urbild Groebner basis in a different degree, the correct one will be automatically reloaded when necessary:: sage: R.load_ugb(2) load Urbild Groebner basis sage: C = COCH(H,1,'C',[1,0]) sage: D = C*C Compute C*C Compose chain maps R_2 > R_1 > R_0 Lift with Urbild Groebner basis in degree 1 load Urbild Groebner basis

makeAutolift
(d)¶ Produce internal data that allow to quickly lift chain maps to one degree.
INPUT:
d – the degree into which it shall be lifted
EXAMPLE:
sage: from pGroupCohomology import CohomologyRing sage: from pGroupCohomology.cochain import COCH sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3, from_scratch=True) sage: R = H.resolution() sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: CohomologyRing.global_options('debug') sage: C = COCH(H,1,'C',[0,1])
For computing a cup product, the necessary lift of a chain map is done with the socalled autolift method, provided it is available. This is not yet the case, so a different, but much slower method (Urbild Groebner bases) is used:
sage: D = C*C Resolution of GF(2)[D8]: Compute C*C Compose chain maps R_2 > R_1 > R_0 Lift with Urbild Groebner basis in degree 1 load Urbild Groebner basis
Now we create the data. And by consequence, a method is used that usually is a bit faster (but the time spent with computing the autolift data should be taken into account as well):
sage: R.makeAutolift(1) Make degree 1 autolift data > import action matrices sage: C = COCH(H,1,'C',[1,0]) sage: D = C*C Compute C*C Compose chain maps R_2 > R_1 > R_0 > Lift with the autolift method

nextDiff
()¶ Compute next unknown differential of the resolution.
EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.reset() sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R Resolution of GF(2)[8gp3]
So far, only term number zero of the resolution was created. We compute up to term number four:
sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: print(R) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2 < rank 3 < rank 4 < rank 5 sage: R[3] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 1 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 1 0] [0 0 0 0 0 0 0 0] [0 1 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 1 0 0] [0 0 1 0 0 0 0 0]

rank
(n=1)¶ Return projective rank(s) of a term or all terms of
self
.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: print(R) Resolution: 0 < GF(2) < GF(2)[8gp3] < rank 2 < rank 3 < rank 4 sage: R.rank() (1, 2, 3, 4) sage: R.rank(2) 3

setLift
(C, n_max)¶ Make a trivial entry in the list of known lifts for a given cochain.
INPUT:
C
, a cochain defined over selfn
, maximal degree to which the cochain shall be lifted
NOTE:
This function should only be of internal use
EXAMPLE:
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: R = H.resolution() sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff()
Now we construct a cochain:
sage: from pGroupCohomology.cochain import COCH sage: C = COCH(H,2,'C',[1,0,1]) sage: R.getLifts() {} sage: R.setLift(C,4) sage: list(R.getLifts().keys()) [(2, 2)]
Hence, now there are cochains (i.e., chain maps) of degree 2 whose lifts are known in degree 2.
sage: list(R.getLifts().values()) [{[1 0 1]: (( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 2, 0, [1 0 0 0 0 0 0 0] ), 4)}]
In fact, the known lift is the trivial one:
sage: R.getLifts()[(2,2)][C.MTX()][0] == R.CochainToChainmap(2,C.MTX()) True

ugb_liftChainMap
(n, d, M)¶ Lift a chain map using Urbild Groebner bases.
INPUT:
 n, d – integers, \(d<n\)
 M – a
Matrix_gfpn_dense
matrix representing a morphism from the \((n1)\)th to the \((d1)\)th term of self.
OUTPUT:
A
Matrix_gfpn_dense
matrix representing the lift to a morphism from the \(n\)th to the \(d\)th term of self.NOTE:
See
RESL
for an explanation of the notion ‘lift’. It certainly is odd that the syntax of this method differs from the syntax ofliftChainMap()
. Sorry.EXAMPLES:
First, we create the basic data for the dihedral group of order 8 (compare
makeGroupData()
):sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, RESL sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: makeGroupData(8,3,folder=tmp_root) sage: gstem='8gp3' sage: gps_folder=os.path.join(tmp_root,gstem) sage: res_folder=os.path.join(gps_folder,'dat') sage: R=RESL(gstem,gps_folder,res_folder) sage: R.nextDiff() sage: R.nextDiff() sage: R.nextDiff() sage: C = MTX(MatrixSpace(GF(2),1,3, implementation=MTX), [[1,0,1]]) sage: c = R.CochainToChainmap(2,C) sage: c ( [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] 2, 0, [1 0 0 0 0 0 0 0] ) sage: cLift = R.ugb_liftChainMap(3,1,c[2]) sage: cLift [1 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0] [0 0 0 1 0 0 0 0] [0 0 0 0 0 0 0 0] [1 0 0 0 0 0 0 0]

yoneda_coboundary
(X, Y, n, i)¶ INPUT:
X, Y
:Matrix_gfpn_dense
matrices representing the terms \(\phi_n^i: P_n\to P_{ni}\) and \(\phi_{n+1}^i: P_{n+1}\to P_{ni+1}\) of an element \(\phi^i\) of degree \(i\) in the Yoneda complex, where \(P_\ast\) is the underlying resolution.n, i
: integers, \(i \le n\).
OUTPUT:
Z
:Matrix_gfpn_dense
matrix representing the term \((\partial \phi^i)_{n+1}: P_{n+1}\to P_{ni}\) representing the Yoneda coboundary of \(\phi^i\).NOTE:
This method is mainly of internal use.
THEORY:
If \(d_\ast: P_\ast \to P_{\ast1}\) denotes the boundary maps of \(P_\ast\) then \((\partial \phi^i)_{n+1} = \phi_n\circ d_{n+1}  (1)^i d_{ni+1}\circ \phi_{n+1}^i\).
TESTS:
sage: from pGroupCohomology import CohomologyRing sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: CohomologyRing.doctest_setup() # reset, block web access, use temporary workspace sage: H = CohomologyRing(8,3) sage: H.make() sage: YC = (H.2.yoneda_cocycle()*H.3.yoneda_cocycle()).find_cobounding_yoneda_cochains() sage: [H.resolution().yoneda_coboundary(Y[0],Y[1],Y.deg(),Y.deg())==Y.coboundary()[0] for Y in YC] [True, True, True, True]

class
pGroupCohomology.resolution.
RESL_sparse_unpickle_class
¶ Used for unpickling class instances of
RESL
.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: R = H.resolution() sage: print(R) Resolution: 0 < GF(2) < GF(2)[D8] < rank 2 < rank 3 < rank 4 sage: R == loads(dumps(R)) # indirect doctest True sage: R is loads(dumps(R)) False

pGroupCohomology.resolution.
baseMTX
(f, m, n, i, j)¶ Return an immutable
Matrix_gfpn_dense
matrix with a single mark1
.INPUT:
f
– integer, the field size.m
,n
– integers, row and column number.i
,j
– integers, position of the single mark1
.
OUTPUT:
An immutable \((m\times n)\)
Matrix_gfpn_dense
matrix over \(GF(f)\) with a single entry1
at \((i,j)\)EXAMPLE:
sage: from pGroupCohomology.resolution import baseMTX sage: baseMTX(3, 4, 5, 1, 2) [0 0 0 0 0] [0 0 1 0 0] [0 0 0 0 0] [0 0 0 0 0]

pGroupCohomology.resolution.
makeGroupData
(q, n, folder, ElAb=False, Forced=False)¶ Create basic data files the cohomology computation of
SmallGroup(q,n)
.INPUT:
q
– the order of some finite \(p\)group \(G\)n
– the number of the group in the SmallGroups libraryfolder
– name of a directory in which the data files will be stored. The directory will be created, if necessary.ElAb
(optional bool, default False) – indicates whether the group is elementary abelian.Forced
(optional bool, default False) – if True, force recomputation.
OUTPUT:
Various files will be created in subdirectories of the specified folder. These files provide information needed to construct a minimal projective resolution of the group, using David Green’s programs.
ALGORITHM:
This function is based on Gap functions written by David Green.
 First, it is checked whether there already are certain files in the
specified directory. If they are, nothing is done, unless the optional
argument
'forced'
is True. The present data are not checked for consistency. So, if data are corrupted, one may empty the folder or simply specify'forced=True'
).  Minimal generators for the group are computed, giving rise to a certain basis of the group algebra \(\mathbb F_pG\).
 The matrices for left and right action of \(G\) on the group algebra are computed.
 The greatest central elementary abelian subgroup of \(G\) and representatives for the conjugacy classes of maximal elementary abelian subgroups of \(G\) are computed.
The data are stored in files.
EXAMPLES:
We construct the data for the dihedral group of order 8, which is number 3 in the SmallGroups library. For illustration, we use logging:
sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, coho_logger sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.global_options('info') sage: makeGroupData(8,3,folder=tmp_root) <module>: Computing basic setup for Small Group number 1 of order 2 Computing basic setup for Small Group number 2 of order 4 Computing basic setup for Small Group number 3 of order 8 sage: CohomologyRing.global_options('warn')
The files defining the basis for the group algebra of the dihedral group and its special subgroups are located in subfolders of
tmp_root
, whose name are given by the order and the SmallGroups library number of the respective group. We call this the stem folder of the group. It looks like this:sage: f = open(os.path.join(tmp_root,'8gp3','8gp3.nontips')) sage: print(f.read()) 2 8 4 3 2 R (1); a; b; ab; ba; aba; bab; baba; sage: f.close() sage: f = open(os.path.join(tmp_root,'4gp2','4gp2.nontips')) sage: print(f.read()) 2 4 2 3 2 R (1); a; b; ba; sage: f.close()
Other files, contained in the subdirectory ‘sgp’ of the stem folder, describe the embedding of the elementary abelian subgroups. The first subgroup will always be the greatest central elementary abelian. Here is a matrix defining the embedding of the third special subgroup, which is elementary abelian of order 4. The matrix is a MeatAxe matrix (see
Matrix_gfpn_dense
).sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: M = MTX.from_filename(os.path.join(tmp_root,'8gp3','sgp','8gp3sg3.ima')) sage: print(M) [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]

pGroupCohomology.resolution.
makeSpecialGroupData
(H, GStem, folder)¶ Creating data files for computing the cohomology of a finite \(p\)Group.
INPUT:
H
– a finite \(p\)group defined in the libgap interfaceGStem
– a string, providing a short and unique descriptor ofH
folder
(optional string) – name of a directory in which the data files will be stored. The directory will be created, if necessary.
OUTPUT:
See
makeGroupData()
NOTE:
In contrast to
makeGroupData()
, this function does not have an optional argumentforced
. So, if corrupted data are present for the given folder and the givenGStem
, they must be removed before invokingmakeSpecialGroupData
.ALGORITHM:
See
makeGroupData()
EXAMPLES:
We construct the data for the dihedral group of order 8. In contrast to the example for
makeGroupData()
, we define it directly in the Gap interface:sage: G = libgap.DihedralGroup(8) sage: GStem = 'DihedralGroup' sage: tmp_root = tmp_dir() sage: from pGroupCohomology.resolution import makeGroupData, makeSpecialGroupData, coho_logger
Again, we log the computation.
sage: from pGroupCohomology import CohomologyRing sage: CohomologyRing.global_options('info') sage: makeSpecialGroupData(G,GStem,folder=tmp_root) <module>: Computing basic setup for Small Group number 1 of order 2 Computing basic setup for Small Group number 2 of order 4 Computing basic setup for DihedralGroup sage: CohomologyRing.global_options('warn')
Now, all data concerning G are in subfolders of the stem folder of G, which is
os.path.join(tmp_root,GStem)
. Also the file names make use of the given GStem. Here are the contents, analogous to the example ofmakeGroupData()
:sage: f = open(os.path.join(tmp_root,GStem,GStem+'.nontips')) sage: print(f.read()) 2 8 4 3 2 R (1); a; b; ba; bb; bba; bbb; bbba; sage: import os sage: sorted(os.listdir(os.path.join(tmp_root,GStem,'sgp'))) ['DihedralGroup.sgs', 'DihedralGroupsg1.ima', 'DihedralGroupsg1.irg', 'DihedralGroupsg2.ima', 'DihedralGroupsg2.irg', 'DihedralGroupsg3.ima', 'DihedralGroupsg3.irg'] sage: from sage.matrix.matrix_gfpn_dense import Matrix_gfpn_dense as MTX sage: M = MTX.from_filename(os.path.join(tmp_root,GStem,'sgp',GStem+'sg3.ima')) sage: print(M) [1 0 0 0 0 0 0 0] [0 0 0 0 1 0 0 0] [0 1 1 1 0 0 0 0] [0 0 0 0 0 1 1 1]
Note that the result is different from the result obtained with
makeGroupData(8,3)
(seemakeGroupData()
): We consider two different presentations of the dihedral group, so the output is not necessarily identical (but certainly isomorphic).