############################################################################# ## ## This file is part of GAP, a system for computational discrete algebra. ## This file's authors include Frank Celler, Alexander Hulpke. ## ## Copyright of GAP belongs to its developers, whose names are too numerous ## to list here. Please refer to the COPYRIGHT file for details. ## ## SPDX-License-Identifier: GPL-2.0-or-later ## ## This file contains the methods for operations for the 1-Cohomology ##
############################################################################# ## #F TriangulizedGeneratorsByMatrix(<gens>,<M>,<F>) ## triangulize and make base ##
InstallGlobalFunction(TriangulizedGeneratorsByMatrix,function (gens,M,F)
local m, n, i, j, k, a, r,z, z0;
gens:=ShallowCopy(gens);
M:=ShallowCopy(M); # get the size of the matrix
m:=Length(M);
n:=Length(M[1]);
# run through all columns of the matrix
z0:=Zero(F);
i :=0; for k in [1 .. n] do
j:=i+1; while j<= m and M[j][k] = z0 do
j:=j+1;
od; if j<= m then
i:=i+1;
z:=M[j][k]^-1;
a:=gens[j]; gens[j]:=gens[i]; gens[i]:=a^IntFFE(z);
r:=M[j]; M[j]:=M[i]; M[i]:=z*r; for j in [1 .. m] do
z:=M[j][k]; if i<>j and z<>z0 then
gens[j]:=gens[j] / (gens[i]^IntFFE(z));
M[j]:=M[j] - z*M[i]; fi;
od;
fi;
od;
n:=[[],[]];
r:=0*M[1]; for i in [1 .. m] do if M[i]<>r then
Add(n[1],gens[i]);
Add(n[2],M[i]); fi;
od;
return n;
end);
## For all following functions,the group is given as second argument to ## allow dispatching after the group type
BindGlobal( "OCAddGeneratorsPcgs", function(ocr,group)
local gens;
if not IsBound(ocr.pcgs) then
ocr.pcgs:=ParentPcgs(NumeratorOfModuloPcgs(ocr.modulePcgs)); fi;
Info(InfoCoh,2,"OCAddGenerators2: using standard generators"); if IsBound(ocr.pPrimeSet) then
Info(InfoCoh,3,"OCAddGenerators2: p prime set is given ", "for standard generating set"); fi; if IsBound(ocr.smallGeneratingSet) then
Info(InfoCoh,3,"OCAddGenerators2: small generating set is given ", "for standard generating set"); fi;
if not IsBound(ocr.generators) then
Info(InfoCoh,2,"setting new generators");
ocr.generators:=InducedPcgs(ocr.pcgs,group)
mod NumeratorOfModuloPcgs(ocr.modulePcgs); fi;
if IsBound(ocr.normalIn) then if not ForAll(ocr.module,i->i in ocr.normalIn) then
gens:=InducedPcgs(ocr.pcgs,ocr.normalIn); else
gens:=AsList(InducedPcgs(ocr.pcgs,ocr.normalIn) mod
ocr.modulePcgs); fi;
ocr.normalGenerators:=gens; fi;
end );
BindGlobal( "OCAddGeneratorsGeneral", function(ocr)
local hom,fg,fpi,fpg,nt,fam;
if IsBound(ocr.normalIn) then
Error("normalizing subgroup not allowed in general case"); fi;
if IsBound(ocr.pPrimeSet) then
Error("p prime set given in general case"); fi;
if IsBound(ocr.factorpres) then # see if factor presentation is known already
return; fi;
nt:=SubgroupNC(ocr.group,NumeratorOfModuloPcgs(ocr.modulePcgs)); if IsBound(ocr.factorfphom) and not IsBound(ocr.generators) then
Info(InfoCoh,1,"using provided presentation");
hom:=ocr.factorfphom;
fpg:=FreeGeneratorsOfFpGroup(Range(hom));
ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(hom))];
ocr.generators:=List(GeneratorsOfGroup(Range(hom)),
i->PreImagesRepresentative(hom,i));
else if (Index(ocr.group,nt)>Size(nt)^3
or Index(ocr.group,nt)>500000) and
(not KnownNaturalHomomorphismsPool(ocr.group,nt) or
DegreeNaturalHomomorphismsPool(ocr.group,nt)>10000) then # computing a factor representation may be too hard
hom:=false; else
hom:=NaturalHomomorphismByNormalSubgroup(ocr.group,nt);
fg:=Image(hom,ocr.group);
ocr.factormap:=hom; fi;
if hom<>false and (IsSolvableGroup(Range(hom))
or (IsPermGroup(Range(hom)) and Length(MovedPoints(Range(hom)))
<Length(MovedPoints(ocr.group))*2)
or (HasIsomorphismFpGroup(fg) and not IsBound(ocr.generators))) then
Info(InfoCoh,1,"using factor representation"); if IsBound(ocr.generators) then
fpi:=IsomorphismFpGroupByGeneratorsNC(fg,List(ocr.generators,
i->Image(hom,i)),"f"); else
fpi:=IsomorphismFpGroup(fg:noshort:=true); fi;
fpg:=FreeGeneratorsOfFpGroup(Range(fpi));
ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fpi)),
List(GeneratorsOfGroup(Range(fpi)),
i->PreImagesRepresentative(fpi,i))]; if not IsBound(ocr.generators) then
ocr.generators:=List(ocr.factorpres[3],i->PreImagesRepresentative(hom,i)); fi;
elif IsBound(ocr.generators) then
Info(InfoCoh,1,"using group representation");
fpi:=IsomorphismFpGroupByGeneratorsNC(ocr.group,ocr.generators,"f"); # else # old code # fpi:=IsomorphismFpGroup(ocr.group:noshort:=true); # ocr.generators:=List(MappingGeneratorsImages(fpi)[2], # i->PreImagesRepresentative(fpi,i)); # fi;
fpg:=FreeGeneratorsOfFpGroup(Range(fpi));
ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fpi))];
# add generating system for ocr.module to obtain a presentation of the # factor group
fpi:= GroupHomomorphismByImagesNC(ocr.group,
FreeGroupOfFpGroup(Range(fpi)),
ocr.generators,fpg);
ocr.factorpres[2]:=Union(ocr.factorpres[2],
List(NumeratorOfModuloPcgs(ocr.modulePcgs),
i->ImagesRepresentative(fpi,i:noshort:=true))); else # build suitable pres for factor
Info(InfoCoh,1,"using group rep and series for factor");
fpi:=IsomorphismFpGroupByChiefSeriesFactor(ocr.group,"f",nt);
fam:=FamilyObj(One(Range(fpi)));
fpg:=FreeGeneratorsOfFpGroup(Range(fpi));
ocr.generators:=List(fpg,i->PreImagesRepresentative(fpi,
ElementOfFpGroup(fam,i)));
ocr.factorpres:=[fpg,RelatorsOfFpGroup(Range(fpi)),ocr.generators]; fi; fi;
# though using the method selection would be nicer,here the decisions are # that involved we actually have to use a dispatcher if IsBound(ocr.inPcComplement) # the pc complement routines interface # directly,giving generators that form an # pcgs
or ((IsPcGroup(G) or
(IsBound(ocr.generators) and IsGeneralPcgs(ocr.generators)))
and not IsBound(ocr.factorpres)) then
OCAddGeneratorsPcgs(ocr,G); else
OCAddGeneratorsGeneral(ocr); fi; end);
# If<ocr>already has a record component 'matrices',nothing is done. if IsBound(ocr.matrices) then
return; fi;
Info(InfoCoh,2,"OCAddMatrices: computes linear operations");
# Construct field and log table.
base:=ocr.modulePcgs;
if Length(base)=0then
Info(InfoCoh,2,"OCAddMatrices: module is trivial");
return; else
ocr.char :=RelativeOrderOfPcElement(base,base[1]);
ocr.field:=GF(ocr.char);
ocr.one:=One(ocr.field);
ocr.zero:=Zero(ocr.field); # logTable is used by 'NextCentralCO'
ocr.logTable:=[]; for i in [1 .. ocr.char - 1] do
ocr.logTable[LogFFE(i*One(ocr.field),
PrimitiveRoot(ocr.field))+1]:=i;
od; fi;
# Do the same for the operations of 'normalIn' if present. if IsBound(ocr.normalIn) then if not IsBound(ocr.normalMatrices) then
ocr.normalMatrices:=LinearOperationLayer(ocr.normalGenerators,
ocr.modulePcgs); # List(ocr.normalMatrices,IsMatrix); fi; fi;
# Construct the inverse of 'moduleMap'.
ocr.vectorMap:=function(v)
local wrd, i;
wrd:=One(ocr.modulePcgs[1]); for i in [1 .. Length(v)] do if v[i]<>ocr.zero then
wrd:=wrd*ocr.modulePcgs[i]^IntFFE(v[i]); fi;
od;
return wrd; end;
# Get the module generators.
base:=ocr.modulePcgs;
dim :=Length(base);
# If 'smallGeneratingSet' is given,neither 'cocycle' nor 'list' need the # entries at the nongenerators. if not IsBound(ocr.cocycleToList) then
Info(InfoCoh,2,"OCAddToFunctions: adding 'cocycleToList'");
ocr.cocycleToList:=function(c)
local w, i, j, k, L;
L:=[];
k:=0; for i in [1 .. Length(c) / dim] do
w:=One(base[1]); for j in [1 .. dim] do if c[k+j]<>ocr.zero then
w:=w*base[j]^IntFFE(c[k+j]); fi;
od;
Add(L,w);
k:=k+dim;
od;
return L; end; fi;
# 'listToCocycle' is almost trivial. if not IsBound(ocr.listToCocycle) then
Info(InfoCoh,2,"OCAddToFunctions: adding 'listToCocycle'");
ocr.listToCocycle:=function(L)
local c, n;
c:=[]; for n in L do
Append(c,ocr.moduleMap(n));
od; #IsRowVector(c);
ConvertToVectorRep(c,ocr.field);
return ImmutableVector(ocr.field,c); end; fi;
# If 'complement' is unknown,the following function does not make sense, # so just return. if not IsBound(ocr.complement) then
Info(InfoCoh,2,"OCAddToFunctions: no complement,returning");
return; fi;
gens:=ocr.complementGens;
# If 'smallGeneratingSet' is not present,just correct 'complement' by # the list 'cocycleToList'. Otherwise we need to compute the correction # with the use of 'bigMatrices' and 'bigVectors'. if not IsBound(ocr.cocycleToComplement) then
Info(InfoCoh,2,"OCAddToFunctions: adding 'cocycleToComplement'"); if not IsBound(ocr.smallGeneratingSet) then
ocr.cocycleToComplement:=function(c)
local L, i;
L:=ocr.cocycleToList(c); for i in [1 .. Length(L)] do
L[i]:=gens[i]*L[i];
od;
return GroupByGenerators(L,One(base[1])); end; else
# Get the correcting list. The nongenerator correction are given # by m_i + n_1*C_ij+... for i a nongenerator index and j a # generator index. m_i is stored in<bigVectors>and C_ij is # stored in<bigMatrices>.
ocr.cocycleToComplement:=function(c)
local L, i, n, j;
L:=[]; for i in [1 .. Length(c) / dim] do
n:=c{[(i-1)*dim+1 .. i*dim]};
L[ocr.smallGeneratingSet[i]]:=n;
od; for i in [1 .. Length(gens)] do if not IsBound(L[i]) then
n:=ocr.bigVectors[i]; for j in ocr.smallGeneratingSet do
n:=n+L[j]*ocr.bigMatrices[i][j];
od;
L[i]:=n; fi;
od; for i in [1 .. Length(L)] do
L[i]:=gens[i]*ocr.vectorMap(L[i]);
od;
return GroupByGenerators(L,One(base[1])); end; fi; fi;
# As the IGS might be used especially here,first do not bind
OCAddToFunctions2(ocr,ocr.generators);
end);
InstallMethod(OCAddToFunctions2,"pc group",true,[IsRecord,IsModuloPcgs], 2,function(ocr,pcgs)
local gens;
gens:=ocr.complementGens;
if not IsBound(ocr.complementToCocycle) then
ocr.origgens:=ocr.generators;
Info(InfoCoh,2,"OCAddToFunctions: adding 'complementToCocycle'"); if not IsBound(ocr.smallGeneratingSet) then
ocr.complementToCocycle:=function(K)
local L, i; # get the generators corresponding to the pcgs
L:=CorrespondingGeneratorsByModuloPcgs(ocr.origgens,
GeneratorsOfGroup(K)); for i in [1 .. Length(gens)] do
L[i]:=LeftQuotient(gens[i],L[i]);
od;
return ocr.listToCocycle(L); end; else
Error("not yet implemented");
ocr.complementToCocycle:=function(K)
local L, S, i, j;
L:=CanonicalPcgs(InducedPcgsByGenerators(ocr.generators,
GeneratorsOfGroup(K)));
S:=[]; for i in [1 .. Length(ocr.smallGeneratingSet)] do
j:=ocr.smallGeneratingSet[i];
S[i] :=LeftQuotient(gens[j],L[j]);
od;
return ocr.listToCocycle(S); end; fi; fi;
end);
InstallMethod(OCAddToFunctions2,"generic",true,[IsRecord,IsList],0, function(ocr,gens)
local Ngens;
gens:=ocr.complementGens;
if not IsBound(ocr.complementToCocycle) then
Info(InfoCoh,2,"OCAddToFunctions: adding 'complementToCocycle'"); if not IsBound(ocr.smallGeneratingSet) then
Ngens:=NumeratorOfModuloPcgs(ocr.modulePcgs);
ocr.complementToCocycle:=function(K)
local L,i,hom; # create a homomorphism to decompose into generators
hom:= GroupHomomorphismByImagesNC(ocr.group,K,
Concatenation(GeneratorsOfGroup(K),Ngens),
Concatenation(GeneratorsOfGroup(K),List(Ngens,i->One(K))));
L:=[]; for i in [1 .. Length(gens)] do
L[i]:=LeftQuotient(gens[i],
ImagesRepresentative(hom,gens[i]));
od;
return ocr.listToCocycle(L); end; else
Error("this should not happen"); fi; fi;
############################################################################# ## #F OCOneCoboundaries(<ocr>) . . . . . . . . . . one cobounds main routine ##
InstallGlobalFunction(OCOneCoboundaries,function(ocr)
local B, S, L, T, i, j;
# Add the important record components for coboundaries. if IsBound(ocr.oneCoboundaries) then
return ocr.oneCoboundaries; fi;
Info(InfoCoh,1,"OCOneCoboundaries: coboundaries and centralizer");
OCAddGenerators(ocr,ocr.group);
OCAddMatrices(ocr,ocr.generators);
# Construct (1 - M[1], ...,1 - M[n]). if IsBound(ocr.smallGeneratingSet) then
S:=ocr.smallGeneratingSet; else
S:=[1 .. Length(ocr.generators)]; fi;
L:=[];
T:=ocr.identityMatrix; for i in [1 .. Length(T)] do
L[i]:=[]; for j in S do
Append(L[i],T[i] - ocr.matrices[j][i]);
od;
od;
IsMatrix(L);
# If there are no equations,return. if Length(S) = 0then
Info(InfoCoh,1,"OCOneCoboundaries: group is trivial");
ocr.oneCoboundaries:=FullRowSpace(ocr.field,0);
ocr.centralizer:=SubgroupNC(ocr.group,ocr.modulePcgs);
return ocr.oneCoboundaries; fi;
# Find a base for the one coboundaries.
B:=TriangulizedGeneratorsByMatrix(ocr.modulePcgs ,L,ocr.field);
ocr.oneCoboundaries:=VectorSpace(ocr.field,B[2],Zero(ocr.field)*L[1]);
ocr.triangulizedBase:=B[1];
Info(InfoCoh,1,"OCOneCoboundaries: |B^1| = ",ocr.char, "^",Dimension(ocr.oneCoboundaries));
ocr.heads:=[];
j:=1;
i:=1; while i<= Length(B[2]) and j<= Length(B[2][1]) do if B[2][i][j]<>ocr.zero then
ocr.heads[i]:=j;
i:=i+1; fi;
j:=j+1;
od;
# Now get the nullspace, this is the centralizer.
OCAddCentralizer(ocr,NullspaceMat(L));
Info(InfoCoh,1,"OCOneCoboundaries: |C| = ",ocr.char, "^",Length(GeneratorsOfGroup(ocr.centralizer)));
OCAddToFunctions(ocr);
return ocr.oneCoboundaries;
end);
############################################################################# ## #F OCConjugatingWord(<ocr>,<c1>,<c2>) . . . . . . . . . . . . . . local ## ## Compute a Word n in<ocr.module>such that<c1>^ n =<c2>. ##
InstallGlobalFunction(OCConjugatingWord,function(ocr,c1,c2)
local B, w, v, j;
B:=ocr.triangulizedBase;
w:=One(ocr.modulePcgs[1]);
v:=c2 - c1; for j in [1 .. Length(ocr.heads)] do #if IntFFE(v[ocr.heads[j]])<>false then
w:=w*B[j]^IntFFE(v[ocr.heads[j]]); #fi;
od;
return w;
# If<ocr>has a record component 'relators',nothing is done. if IsBound(ocr.relators) then
return; fi;
Info(InfoCoh,2,"OCAddRelations: computes pc-presentation");
# Construct the factor pcgs
mpcgs :=ocr.generators;
# Start with the power-relations. If g1^p = g2^3*g4^5*g5,then # the relator g1 ^ -p * g2 ^ 3 *g4^5*g5 is used,because it # contains only one negative exponent.
ocr.relators:=[]; for i in [1 .. Length(mpcgs)] do
p:=RelativeOrders(mpcgs)[i];
r:=rec(generators:=[i],powers:=[-p] );
w:=ExponentsOfRelativePower(mpcgs,i); for j in [1 .. Length(w)] do if w[j]<>0then
Add(r.generators,j);
Add(r.powers,w[j]); fi;
od;
r.usedGenerators:=Set(r.generators);
Add(ocr.relators,r);
od;
# Now compute the conjugated words. If g1^g2 = g3^5*g4^2,then # the relator (g1^-1)^g2*g3^5*g4^2 is used,as it contains # only two negative exponents. for i in [1 .. Length(mpcgs) - 1] do for j in [i+1 .. Length(mpcgs)] do
r:=rec(generators:=[i,j,i],powers:=[-1,-1,1]);
w:=mpcgs[j]^mpcgs[i];
w:=ExponentsOfPcElement(mpcgs,w); for k in [1 .. Length(w)] do if w[k]<>0then
Add(r.generators,k);
Add(r.powers,w[k]); fi;
od;
r.usedGenerators:=Set(r.generators);
Add(ocr.relators,r);
od;
od;
end);
InstallMethod(OCAddRelations,"perm group",true,[IsRecord,IsList],0, function(ocr,gens )
local r,rel,i,j,w;
# If<ocr>has a record component 'relators',nothing is done. if IsBound(ocr.relators) then
return; fi;
Info(InfoCoh,2,"OCAddRelations: fetch presentation");
# it is not the right place to get a presentation here,as we may have # chosen the wrong generators before. So we just fetch it.
r:=ocr.factorpres[2];
# now rewrite the relators into the OC form
ocr.relators:=[];
for i in r do
rel:=rec(generators:=[],powers:=[]);
w:=ExtRepOfObj(i);
j:=1; while j<Length(w) do
Add(rel.generators,w[j]);
Add(rel.powers,w[j+1]);
j:=j+2;
od;
BindGlobal("OCTestRelations",function(ocr,gens)
local i,j,e,g;
g:=GroupByGenerators(NumeratorOfModuloPcgs(ocr.modulePcgs)); for i in ocr.relators do
e:=One(gens[1]); for j in [1..Length(i.generators)] do
e:=e*gens[i.generators[j]]^i.powers[j];
od; if not e in g then
Error("relator wrong"); fi;
od;
return true; end);
############################################################################# ## #M NormalRelations(<ocr>,<G>,<gens>) . . rels for normal complements,local ##
InstallMethod(OCNormalRelations,"pc group",
true,[IsRecord,IsPcGroup,IsListOrCollection],0, function(ocr,G,gens)
local i,j,k,
relations,
r,
w,mpcgs;
Info(InfoCoh,2,"computes rels for normal complements");
Error("this still has to be fixed!");
mpcgs:=InducedPcgsByGeneratorsNC(ocr.pcgs,
Concatenation(ocr.generators,ocr.modulePcgs)) mod
ocr.modulePcgs; # Compute g_i^s_j for all generators s_j in 'normalGenerators' and all # i in<generators>.
relations:=[]; for i in [1 .. Length(gens)] do for j in [1 .. Length(ocr.normalGenerators)] do
r:=rec(generators:=[],
powers :=[],
conjugated:=[i,j]);
w:=ocr.generators[gens[i]]^ocr.normalGenerators[j];
w:=ExponentsOfPcElement(mpcgs,w); for k in [1 .. Length(w)] do if w[k]<>0then
Add(r.generators,k);
Add(r.powers,w[k]); fi;
od;
r.usedGenerators:=Set(r.generators);
Add(relations,r);
od;
od;
return relations;
if not IsBound(ocr.maximalPowers) then
Info(InfoCoh,2,"maximal powers = relative orders");
ocr.maximalPowers:=List(ocr.generators,
i->RelativeOrderOfPcElement(pcgs,i)); fi;
# At first add all powers, such that powerMatrices[ i ][ j] is # matrices[ i ] ^j for j = 1 ... p,if p is the maximal power for the # i.th generator. if not IsBound(ocr.powerMatrices) then
Info(InfoCoh,2,"AddSumMatrices: adding power matrices");
ocr.powerMatrices:=[]; for i in [1 .. Length(ocr.matrices)] do
ocr.powerMatrices[i]:=[ocr.matrices[i]]; for j in [2 .. ocr.maximalPowers[i]] do
ocr.powerMatrices[i][j] :=
ocr.powerMatrices[i][j - 1]*ocr.matrices[i];
od;
od; fi;
# Now all sums, such that sumMatrices[i][j] is the sum from k = 0 # up to j - 1 over matrices[i]^k for j = 1 ... p. if not IsBound(ocr.sumMatrices) then
Info(InfoCoh,2,"AddSumMatrices: adding sum matrices");
ocr.sumMatrices:=[]; for i in [1 .. Length(ocr.matrices)] do
ocr.sumMatrices[i]:=[ocr.identityMatrix]; for j in [2 .. ocr.maximalPowers[i]] do
ocr.sumMatrices[i][j] :=
ocr.sumMatrices[i][j-1]+ocr.powerMatrices[i][j-1];
od;
od; fi;
end);
InstallMethod(OCAddSumMatrices,"perm group",true,[IsRecord,IsList],0, function(ocr,gens)
local i,j;
if not IsBound(ocr.maximalPowers) then
Info(InfoCoh,2,"AddSumMatrices: maximal power = 1");
ocr.maximalPowers:=List(ocr.generators,x->1); fi;
# At first add all powers, such that powerMatrices[ i ][ j] is # matrices[ i ] ^j for j = 1 ... p,if p is the maximal power for the # i.th generator. if not IsBound(ocr.powerMatrices) then
Info(InfoCoh,2,"AddSumMatrices: adding power matrices");
ocr.powerMatrices:=[]; for i in [1 .. Length(ocr.matrices)] do
ocr.powerMatrices[i]:=[ocr.matrices[i]]; for j in [2 .. ocr.maximalPowers[i]] do
ocr.powerMatrices[i][j] :=
ocr.powerMatrices[i][j - 1]*ocr.matrices[i];
od;
od; fi;
# Now all sums, such that sumMatrices[i][j] is the sum from k = 0 # up to j - 1 over matrices[i]^k for j = 1 ... p. if not IsBound(ocr.sumMatrices) then
Info(InfoCoh,2,"AddSumMatrices: adding sum matrices");
ocr.sumMatrices:=[]; for i in [1 .. Length(ocr.matrices)] do
ocr.sumMatrices[i]:=[ocr.identityMatrix]; for j in [2 .. ocr.maximalPowers[i]] do
ocr.sumMatrices[i][j] :=
ocr.sumMatrices[i][j-1]+ocr.powerMatrices[i][j-1];
od;
od; fi;
end);
############################################################################# ## #F OCEquationMatrix(<ocr>,<r>,<n>) . . . . . . . . . . . . . . . local ##
InstallGlobalFunction(OCEquationMatrix,function(ocr,r,n)
local mat, i, j, v, vv;
Info(InfoCoh,3,"OCEquationMatrix: matrix number ",n);
mat:=ocr.identityMatrix - ocr.identityMatrix; if not n in r.usedGenerators then return mat; fi;
# For j:=generators[i], v:=powers[i], M operations: # # if j = n and v>0,then # mat = mat*M[j]^v+sum_{k=0}^{v-1} M[j]^k # if j = n and v<0,then # mat = (mat - sum_{k=0}^{-v-1} M[j]^k)*M[j]^v # if j<>n,then # mat = mat*M[j]^v # for i in [1 .. Length(r.generators)] do
j :=r.generators[i];
vv:=r.powers[i];
# Repeat,until we used up all powers. while vv<>0do if AbsInt(vv)>AbsInt(ocr.maximalPowers[j]) then
v :=SignInt(vv)*ocr.maximalPowers[j];
vv:=vv - v; else
v :=vv;
vv:=0; fi; if j = n and v>0then
mat:=mat*ocr.powerMatrices[j][v]+ocr.sumMatrices[j][v]; elif j = n and v<0then
mat:= (mat - ocr.sumMatrices[j][-v])
*(ocr.powerMatrices[j][-v]^-1); elif j<>n and v>0then
mat:=mat*ocr.powerMatrices[j][v]; elif j<>n and v<0then
mat:=mat*(ocr.powerMatrices[j][-v]^-1); else
Info(InfoCoh,2,"OCEquationMatrix: zero power"); fi;
od;
od;
# if<r> has an entry 'conjugated' the records is no relator for a # presentation,but belongs to relation # (g_i n_i)^s_j = r # which is used to determinate normal complements. [i,j] is bound to # 'conjugated'. If i<><n>,we can forget about it,but otherwise -s_j # must be added. if IsBound(r.conjugated) and r.conjugated[1] = n then
mat:=mat - ocr.normalMatrices[r.conjugated[2]]; fi;
return mat;
end);
############################################################################# ## #M OCAddBigMatrices(<ocr>,<generators>) . . . . . . . . . . . . . local ##
InstallMethod(OCAddBigMatrices,"general",true,[IsRecord,IsList],0, function(ocr,G)
local i, j, n, w, small, nonSmall;
# If no small generating set is known simply return. if not IsBound(ocr.smallGeneratingSet) then
Info(InfoCoh,2,"AddBigMatrices: no small generating set");
return; fi;
small:=ocr.smallGeneratingSet;
nonSmall:=Difference([1 .. Length(ocr.generators)],small); if not IsBound(ocr.bigMatrices) then
ocr.bigMatrices:=List([1 .. Length(ocr.generators)],x->[]);
Info(InfoCoh,2,"AddBigMatrices: adding bigMatrices"); for i in nonSmall do for j in small do
ocr.bigMatrices[i][j]:=OCEquationMatrix(ocr,
ocr.generatorsInSmall[i],j);
od;
od; fi;
# Compute n_(i) for non small generators i. if not IsBound(ocr.bigVectors) then
Info(InfoCoh,2,"AddBigMatricesOC: adding bigVectors");
ocr.bigVectors:=[]; for i in nonSmall do
n:=ocr.generators[i]^-1;
w:=ocr.generatorsInSmall[i]; for j in [1 .. Length(w.generators)] do
n:=n*ocr.generators[w.generators[j]]^w.powers[j];
od;
ocr.bigVectors[i]:=ocr.moduleMap(n);
od; fi;
end);
############################################################################# ## #F OCSmallEquationMatrix(<ocr>,<r>,<n>) . . . . . . . . . . . . . local ##
InstallGlobalFunction(OCSmallEquationMatrix,function(ocr,r,n)
local mat, i, j, v, vv;
Info(InfoCoh,3,"OCSmallEquationMatrix: matrix number ",n);
mat:=ocr.identityMatrix - ocr.identityMatrix;
#<n>must a small generator. if not n in ocr.smallGeneratingSet then
Error("<n> is no small generator"); fi;
# Warning: if<n>is not in <r.usedGenerators>we cannot return,as the # nonsmall generators may yield a result.
# For j:=generators[i], v:=powers[i], M operations: # # If j is a small generator,everything is as usual. # # if j = n and v>0, then # mat = mat*M[j]^v+sum_{k=0}^{v-1} M[j]^k # if j = n and v<0, then # mat = (mat - sum_{k=0}^{-v-1} M[j]^k)*M[j]^v # if j<>n,then # mat = mat*M[j]^v # # If j is not a small generator, then j<>n. But we need to correct #<mat>using the<bigMatrices>: # # n_j = n_(j)+...+n_n^C_jn+... # # if v>0,then # mat = mat*M[j]^v+C_jn*sum_{k=0}^{v-1} M[j]^k # If v<0,then # mat = (mat - C_jn*sum_{k=0}^{-v-1} M[j]^k)*M[j]^v # for i in [1 .. Length(r.generators)] do
j :=r.generators[i];
vv:=r.powers[i]; while vv<>0do if AbsInt(vv)>AbsInt(ocr.maximalPowers[j]) then
v :=SignInt(vv)*ocr.maximalPowers[j];
vv:=vv - v; else
v :=vv;
vv:=0; fi; if j in ocr.smallGeneratingSet then if j = n and v>0then
mat:=mat*ocr.powerMatrices[j][v]
+ocr.sumMatrices[j][v]; elif j = n and v<0then
mat:=(mat - ocr.sumMatrices[j][-v])
*(ocr.powerMatrices[j][-v]^-1); elif j<>n and v>0then
mat:=mat*ocr.powerMatrices[j][v]; elif j<>n and v<0then
mat:=mat*(ocr.powerMatrices[j][-v]^-1); else
Info(InfoCoh,2,"EquationMatrixOC: zero power"); fi; else if v>0then
mat:=mat*ocr.powerMatrices[j][v]
+ocr.bigMatrices[j][n]*ocr.sumMatrices[j][v]; elif v<0then
mat:=(mat-ocr.bigMatrices[j][n]*ocr.sumMatrices[j][-v])
*(ocr.powerMatrices[j][-v]^-1); else
Info(InfoCoh,2,"EquationMatrixOC: zero power"); fi; fi;
od;
od;
# If<r> has an entry <conjugated> the records is no relator for a # presentation,but belongs to relation # (g_i n_i)^s_j =<r> # which is used to determinate normal complements. [i,j] is bound to # 'conjugated'. If i<><n>,we can forget about it,but otherwise s_j # must be added. i is always a small generator. if IsBound(r.conjugated) and r.conjugated[1] = n then
mat:=mat - ocr.normalMatrices[r.conjugated[2]]; fi;
return mat;
# If <r> has an entry 'conjugated' the records is no relator for a # presentation,but belongs to relation # (g_i n_i)^s_j =<r> # which is used to determinate normal complements. [i,j] is bound to # <conjugated>. if IsBound(r.conjugated) then
n:=(ocr.generators[r.conjugated[1]]
^ocr.normalGenerators[r.conjugated[2]])^-1; else
n:=ocr.identity; fi;
for i in [1 .. Length(r.generators)] do
n:=n*ocr.generators[r.generators[i]]^r.powers[i];
od;
Assert(1,n in GroupByGenerators(NumeratorOfModuloPcgs(ocr.modulePcgs)));
return ShallowCopy(ocr.moduleMap(n));
end);
############################################################################# ## #F OCSmallEquationVector(<ocr>,<r>) . . . . . . . . . . . . . . . . local ##
InstallGlobalFunction(OCSmallEquationVector,function(ocr,r)
local n, a, i, nonSmall, v, vv, j;
# if<r>has an entry 'conjugated' the records is no relator for a # presentation,but belongs to relation # (g_i n_i)^s_j =<r> # which is used to determinate normal complements. [i,j] is bound to # 'conjugated'. i is always a small generator. if IsBound(r.conjugated) then
n:=(ocr.generators[r.conjugated[1]]
^ocr.normalGenerators[r.conjugated[2]])^-1; else
n:=ocr.identity; fi;
# At first the vector of the relator itself. for i in [1 .. Length(r.generators)] do
n:=n*ocr.generators[r.generators[i]]^r.powers[i];
od;
n:=ocr.moduleMap(n);
# Each non small generators in<r>gives an additional vector. It # must be shifted through the relator.
nonSmall:=Difference([1 .. Length(ocr.generators)],
ocr.smallGeneratingSet);
a:=n - n; for i in [1 .. Length(r.generators)] do
j :=r.generators[i];
vv:=r.powers[i]; while vv<>0do if AbsInt(vv)>AbsInt(ocr.maximalPowers[j]) then
v :=SignInt(vv)*ocr.maximalPowers[j];
vv:=vv - v; else
v :=vv;
vv:=0; fi;
if j in nonSmall then if v>0then
a:=a*ocr.powerMatrices[j][v]+ocr.bigVectors[j]
*ocr.sumMatrices[j][v]; elif v<0then
a:=(a - ocr.bigVectors[j]
*ocr.sumMatrices[j][-v])
*(ocr.powerMatrices[j][-v]^-1); else
Info(InfoCoh,2,"OCSmallEquationVector: zero power"); fi; else if v>0then
a:=a*ocr.powerMatrices[j][v]; elif v<0then
a:=a*(ocr.powerMatrices[j][-v]^-1); else
Info(InfoCoh,2,"OCSmallEquationVector: zero power"); fi; fi;
od;
od;
############################################################################# ## #F OCOneCocycles(<ocr>,<onlySplit>) . . . . . . one cocycles main routine ## ## If<onlySplit>,'OCOneCocycles' returns 'false' as soon as possibly if ## the extension does not split. ##
InstallGlobalFunction(OCOneCocycles,function(ocr,onlySplit)
local cobounds,cocycles, # base of one coboundaries and cocycles
dim, # dimension of module
gens, # generator numbers
len, # number of generators
K, # list of complement generators
L0, # null vector
S, R, # linear system and right hand side
rels, # relations
RS, RR, # rel linear system and right hand side
isSplit, # is split extension
N, # correct
row, # one row
tmp,i,g,j,k,n;
# If we know our cocycles return them. if IsBound(ocr.oneCocycles) then
return ocr.oneCocycles; fi;
# Assume it does split. This may change later.
isSplit:=true;
ocr.identity:=One(ocr.modulePcgs[1]);
Info(InfoCoh,1,"OCOneCocycles: computes cocycles and cobounds");
# We need the generators of the factorgroup with relations,all matrices # and the cobounds. If the 'smallGeneratingSet' is given,get the big # matrices and vectors.
cobounds:=BasisVectors(Basis(OCOneCoboundaries(ocr)));
# If we are only want normal complements,the group of cobounds must be # trivial, otherwise there are no normal ones as the conjugated # complements correspond with the cobounds. if IsBound(ocr.normalIn) and cobounds<>[] then
Info(InfoCoh,1,"OneCocyclesCO: no normal complements");
return false; fi;
# Initialize the relations and sum/big matrices.
OCAddRelations(ocr,ocr.generators);
Assert(1,OCTestRelations(ocr,ocr.generators)=true);
OCAddSumMatrices(ocr,ocr.generators); if IsBound(ocr.smallGeneratingSet) then
OCAddBigMatrices(ocr,ocr.generators); fi;
# Now initialize a matrix with will hold the triangulized system of # linear equations. If 'smallGeneratingSet' is given use this, if # 'pPrimeSet' is given do not use those.
dim:=Length(ocr.modulePcgs); if IsBound(ocr.smallGeneratingSet) then
gens:=ocr.smallGeneratingSet;
len :=Length(ocr.smallGeneratingSet);
K :=ShallowCopy(ocr.generators); elif IsBound(ocr.pPrimeSet) then
Info(InfoCoh,2,"OCOneCocycles: computing coprime complement");
gens:=Difference([1 .. Length(ocr.generators)],ocr.pPrimeSet);
gens:=Set(gens);
len :=Length(ocr.generators) - Length(ocr.pPrimeSet);
K :=OCCoprimeComplement(ocr,ocr.generators);
ocr.generators:=ShallowCopy(K); else
len :=Length(ocr.generators);
gens:=[1 .. len];
K :=ShallowCopy(ocr.generators); fi;
Info(InfoCoh,2,"OCOneCocycles: ",len," generators");
# Get the linear system for one relation and append it to the already # triangulized system.
Info(InfoCoh,2,"OCOneCocycles: constructing linear equations: ");
# Get all relations. if IsBound(ocr.normalIn) then
rels:=Concatenation(ocr.relators,
OCNormalRelations(ocr,ocr.group,gens)); else
rels:=ocr.relators; fi;
for i in [1 .. Length(rels)] do
Info(InfoCoh,2," relation ",i," (",Length(rels),")");
RS:=[]; if IsBound(ocr.smallGeneratingSet) then for g in gens do
Append(RS,OCSmallEquationMatrix(ocr,rels[i],g));
od;
RR:=OCSmallEquationVector(ocr,rels[i]);
MultVector(RR,-One(ocr.field));
else for g in gens do
Append(RS,OCEquationMatrix(ocr,rels[i],g));
od;
RR:=OCEquationVector(ocr,rels[i]);
MultVector(RR,-One(ocr.field));
fi;
# The is a system for x M = v so transpose.
RS:=MutableTransposedMat(RS);
# Now append this to the triangulized system. for j in [1 .. Length(RS)] do
k:=1; while RS[j]<>L0 do while RS[j][k] = ocr.zero do
k:=k+1;
od; if S[k][k]<>ocr.zero then
RR[j]:=RR[j] - RS[j][k]*R[k];
RS[j]:=RS[j] - RS[j][k]*S[k]; else
R[k]:=RS[j][k]^-1*RR[j];
S[k]:=RS[j][k]^-1*RS[j];
RS[j]:=L0;
RR[j]:=0*RR[j]; fi;
od; if RR[j] <>ocr.zero then
Info(InfoCoh,1,"OCOneCocycles: no split extension");
isSplit:=false; if onlySplit then
return isSplit; fi; fi;
od;
IsMatrix(RS);
od;
# Now remove all entries above the diagonal. Let's see if a solution # exist. As system <S> is triangulized all we have to do,is to check if # right side <R> is null,where the diagonal is null.
Info(InfoCoh,2,"OCOneCocycles: computing nullspace and solution"); for i in [1 .. Length(S)] do if S[i][i]<>ocr.zero then for k in [1 .. i-1] do if S[k][i]<>ocr.zero then
R[k]:=R[k] - S[k][i]*R[i];
S[k]:=S[k] - S[k][i]*S[i]; fi;
od; else if R[i]<>ocr.zero then
Info(InfoCoh,1,"OCOneCocycles: no split extension");
isSplit:=false; if onlySplit then
return isSplit; fi; fi; fi;
od;
# As <system>is triangulized,the right side is now the solution. So if # 'smallGeneratingSet' is not given, we only need to modify the #<complement> generators, which are not in 'pPrimeSet'. Otherwise we # must blow up the cocycle to cover all generators not only the small # ones. if isSplit then if not IsBound(ocr.smallGeneratingSet) then
N:=ocr.cocycleToList(R); for i in [1 .. Length(N)] do
K[gens[i]]:=K[gens[i]]*N[i];
od; else
N:=[]; for i in [1 .. Length(R) / dim] do
n:= R{ [(i-1)*dim+1 .. i*dim] };
N[ocr.smallGeneratingSet[i]]:=n;
od; for i in [1 .. Length(K)] do if not IsBound(N[i]) then
n:=ocr.bigVectors[i]; for j in ocr.smallGeneratingSet do
n:=n+N[j]*ocr.bigMatrices[i][j];
od; else
n:=N[i]; fi;
K[i]:=K[i]*ocr.vectorMap(n);
od; fi;
OCAddComplement(ocr,ocr.group,K);
OCAddToFunctions(ocr); fi;
# System<S>is triangulized, get the nullspace.
cocycles:=[]; for i in [1 .. Length(S[1])] do if S[i][i] = ocr.zero then
row:=ShallowCopy(L0); for k in [1 .. i-1] do
row[k]:=S[k][i];
od;
row[i]:=- One(ocr.field);
Add(cocycles,row); fi;
od;
IsMatrix(cocycles);
# If 'pPrimeSet' is given, we need to add zeros to cocycle at the # positions of the pPrimeGenerators. Then the cobounds must be added in # order to get all cocycles. if IsBound(ocr.pPrimeSet) then
tmp:=ocr.moduleMap(ocr.identity); for j in [1 .. Length(cocycles)] do
k:=0;
row:=[]; for i in [1 .. Length(ocr.generators)] do if not i in ocr.pPrimeSet then
n:=cocycles[j]{ [k*dim+1 .. (k+1)*dim] };
Append(row,n);
k:=k+1; else
Append(row,tmp); fi;
od; #IsRowVector(row);
cocycles[j]:=ImmutableVector(ocr.field,row);
od;
Append(cocycles,cobounds); if cocycles<>[] then
cocycles:=BaseMat(cocycles); fi; else if cocycles<>[] then
TriangulizeMat(cocycles); fi; fi;
ocr.oneCocycles:=VectorSpace(ocr.field,cocycles,
Zero(ocr.oneCoboundaries));
Info(InfoCoh,1,"OCOneCocycles: order of cocycles ",ocr.char, "^",Dimension(ocr.oneCocycles));
return ocr.oneCocycles;
############################################################################# ## #F ComplementClassesRepresentativesEA(<G>,<N>) . complement classes to el.ab. N by 1-Cohom. ##
InstallGlobalFunction(ComplementClassesRepresentativesEA,function(g,n)
local oc,l; if Size(g)=Size(n) then
return TrivialSubgroup(g); fi;
oc:=OneCocycles(g,n); if not oc.isSplitExtension then
return []; else if Dimension(oc.oneCocycles)=Dimension(oc.oneCoboundaries) then
return [oc.complement]; else
l:=BaseSteinitzVectors(BasisVectors(Basis(oc.oneCocycles)),
BasisVectors(Basis(oc.oneCoboundaries)));
l:=List(VectorSpace(LeftActingDomain(oc.oneCocycles),l.factorspace,
Zero(oc.oneCocycles)),
i->oc.cocycleToComplement(i));
return l; fi; fi; end);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.