GAP 4.8.9 installation with standard packages -- copy to your CoCalc project to get it
############################################### ############################################### InstallGlobalFunction(RadicalSeriesOfResolution, function(R) local G, ordG, FG, FGdims, Tdims, T,L,prime, Dimension, FDimension, Boundary, BoundRec, IntToPair, one, PairToInt, cnt, Mult, invT, n, i,g, j, k, r, WordToVectorList, VectorListToWord ; G:=R!.group; ordG:=Order(G); prime:=Factors(ordG)[1]; ################### ################### if not (IsPrime(EvaluateProperty(R,"characteristic")) and IsPrimePowerInt(ordG)) then Print("The resolution must have prime characteristic for a prime-power group\n"); return fail; fi; ################### ################### one:=One(GF(prime)); ################### Mult:=function(g,h); return Position(R!.elts,R!.elts[g]*R!.elts[h]); end; ################### ################### FG:=GroupAlgebraAsFpGModule(G); L:=RadicalSeriesOfFpGModule(FG);; L:=L{[1..Length(L)-1]}; L:=Reversed(L); T:=List(L,x->GeneratorsOfFpGModule(x)); FGdims:=List(T,Length); Tdims:=1*FGdims; for i in [2..Length(FGdims)] do FGdims[i]:=FGdims[i]+FGdims[i-1]; od; T:=Concatenation(T); ##So T is the new basis invT:=T^-1; ################### ################### Dimension:=function(n); if n>Length(R) then return 0; fi; return ordG*R!.dimension(n); end; ################### ################### FDimension:=function(k,n); if n>Length(R) then return 0; fi; return FGdims[k]*R!.dimension(n); end; ################### ################################## IntToPair:=List([0..Length(R)],i->[]); PairToInt:=List([0..Length(R)],i->List([1..R!.dimension(i)], j->[])); # so i --> [r,g] where r is the FG summand and g is the (new basis) position # in summand for n in [0..Length(R)] do cnt:=0; for j in [1..Length(Tdims)] do for g in [1..Tdims[j]] do for r in [1..R!.dimension(n)] do cnt:=cnt+1; IntToPair[n+1][cnt]:=[r,g]; if j>1 then IntToPair[n+1][cnt][2]:=IntToPair[n+1][cnt][2]+FGdims[j-1]; fi; PairToInt[n+1][IntToPair[n+1][cnt][1]][IntToPair[n+1][cnt][2]]:=cnt; od; od; od; od; ################################ ##################################################################### WordToVectorList:=function(w,k) #w is a FG-word in R_k. local v,x,r; #v is a list of vectors mod p. v:=List([1..R!.dimension(k)],i->List([1..ordG],j->0*one) ); for x in w do r:=AbsInt(x[1]); v[r][x[2]]:=v[r][x[2]] + SignInt(x[1])*one; od; return v ; end; ##################################################################### ##################################################################### VectorListToWord:=function(v,n) #returns a sparse word over F. local w, r, g, vv; w:=[]; for r in [1..Length(v)] do for g in [1..Length(v[r])] do if not IsZero(v[r][g]) then Add(w,[PairToInt[n+1][r][g],v[r][g]]); fi; od; od; return w; end; ##################################################################### BoundRec:=List([1..Length(R)],i->[]);; ################################### Boundary:=function(n,k) local w, x,b, bnd, pr, gg,i; if IsBound(BoundRec[n][AbsInt(k)]) then if SignInt(k)>0 then return 1*BoundRec[n][k]; else return NegateWord(BoundRec[n][k]); fi; fi; pr:=IntToPair[n+1][AbsInt(k)]; r:=pr[1]; g:=pr[2]; w:=T[g]; gg:=[]; for i in [1..Length(w)] do for j in [1..IntFFE(w[i])] do Add(gg,i); od; od; w:=R!.boundary(n,r); #This is an FG-word bnd:=[]; for i in gg do b:=List(w, x->[x[1],Mult(i,x[2])]); Append(bnd,b); od; bnd:=WordToVectorList(bnd,n-1); for i in [1..Length(bnd)] do if not IsZero(bnd[i]) then bnd[i]:=bnd[i]*invT; fi; od; bnd:=VectorListToWord(bnd,n-1); BoundRec[n][AbsInt(k)]:=bnd; if SignInt(k)=1 then return 1*bnd; else return NegateWord(bnd); fi; end; ################### return Objectify(HapFilteredSparseChainComplex, rec( dimension:=Dimension, boundary:=Boundary, filteredDimension:=FDimension, properties:=[ ["length",Length(R)], ["filtration_length",Length(FGdims)], ["type","FilteredChainComplex"], ["characteristic",prime]] )); end); ############################################### ###############################################