Spracherkennung für: .gi vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]
#####################################################
# Given a simple algebra output by WedderburnDecompositionInfo
# or SimpleAlgebraByCharacterInfo from wedderga,
# this program determines its actual matrix degree and division
# algebra part in terms of local indices at all primes.
#####################################################
#############################################
# Necessary arithmetic functions for subroutines
#############################################
InstallGlobalFunction( PPartOfN, function(n,p)
local i,a,b;
b:=n;
a:=0;
while IsPosInt(b/p) do
b:=b/p;
a:=a+1;
od;
return p^a;
end);
###############################
InstallGlobalFunction( PDashPartOfN, function(n,p)
local m;
m:=n;
while IsPosInt(m/p) do
m:=m/p;
od;
return m;
end);
#########################################
# Cyclotomic reciprocity functions for the extension
# F(E(n))/F at the prime p. These calculate the
# splitting degree g(F(E(n))/F,p),
# residue degree f(F(E(n))/F,p), and
# ramification index e(F(E(n))/F,p). Using
# suitable quotients of these, one can obtain
# the e, f, and g for any extension K/F of
# abelian number fields.
#########################################
InstallGlobalFunction( PSplitSubextension, function(F,n,p)
local a,y1,L,i,n1,n0,f,L1,b,F1;
a:=PrimitiveElement(F);
L:=[];
for i in [1..n] do
if Gcd(i,n)=1 and GaloisCyc(a,i)=a then
Add(L,i);
fi;
od;
n1:=PDashPartOfN(n,p);
f:=1;
if n1>1 then
while not(PowerMod(p,f,n1)= 1) do
f:=f+1;
od;
fi;
n0:=PPartOfN(n,p);
L1:=[];
for b in L do
if GaloisCyc(E(n1),b)=E(n1) then
AddSet(L1,b);
else
for i in [1..f] do
if b mod n1 = PowerMod(p,i,n1) then
AddSet(L1,b);
fi;
od;
fi;
od;
F1:=NF(n,L1);
######bugfix-not returning extension of F-04/04/2020#######
y1:=PrimitiveElement(F1);
F1:=Field([a,y1]);
#########################################################
return F1;
end);
###################################
InstallGlobalFunction( SplittingDegreeAtP, function(F,n,p)
local K,g;
K:=PSplitSubextension(F,n,p);
g:=Trace(K,F,1);
return g;
end);
###################################
InstallGlobalFunction( ResidueDegreeAtP, function(F,n,p)
local K,a,n1,L,f;
K:=PSplitSubextension(F,n,p);
a:=PrimitiveElement(K);
n1:=PDashPartOfN(n,p);
L:=Field([a,E(n1)]);
f:=Trace(L,K,1);
return f;
end);
#################################
InstallGlobalFunction( RamificationIndexAtP, function(F,n,p)
local n0,n1,a,U,i,U1,e;
a:=PrimitiveElement(F);
n0:=Conductor([a,E(n)]);
U:=[];
for i in [1..n0] do
if Gcd(i,n0)=1 and GaloisCyc(a,i)=a then
Add(U,i);
fi;
od;
n1:=PDashPartOfN(n0,p);
U1:=[];
for i in U do
if GaloisCyc(E(n1),i)=E(n1) then
Add(U1,i);
fi;
od;
e:=Size(U1);
return e;
end);
#################################
# (27/03/2020) Character Descent Functions
# - added by Allen Herman to optimize Clifford theory reductions
# needed for the Local Index functions to give correct output,
# this fixes the bug created by the new WedderburnDecompositionInfo
# command outputting crossed product algebras that are wildly
# ramified at odd primes, which the Local Index functions were
# not designed to handle.
##################################
################################################
# 2) Add a new Global Splitting function that
# reduces algebras whose factor set has too
# many zeroes or is globally trivial.
################################################
InstallGlobalFunction( GlobalSplittingOfCyclotomicAlgebra, function(A)
local A1,m,F,a1,m1,a,b,c,n,m2,g,g1,g2,g3,b1,c1,a2,b2,c2,F1,f,F2,t,d,d1,b11,i,j,cont;
A1:=A;
if Length(A)=5 then
F:=A[2];
if ForAll(A[4],x->x[3]=0) and ForAll(A[5],x->ForAll(x,y->y=0)) then
return [A[1]*Product(A[4],x->x[1]),F];
fi;
A:=A1;
###########################################################################
# (01/04/2020) PUTTING ZEROES IN THE FIFTH ENTRY OF A CYCLOTOMIC ALGEBRA
# WITH ARBITRARY NUMBER OF GENERATORS FOR THE GALOIS GROUP
###########################################################################
if Length(A)=5 then
A1:=KillingCocycle(A);
fi;
while A1<>fail do
A:=A1;
A1:=ReducingCyclotomicAlgebra(A);
od;
fi;
A1:=A;
if Length(A) = 4 then
F:=A[2];
a1:=PrimitiveElement(F);
m1:=A[3];
a:=A[4][1];
b:=A[4][2];
c:=A[4][3];
n:=Conductor(F);
if IsOddInt(n) then
n:=2*n;
fi;
for m2 in [1..n] do
if E(n)^m2 in F then
break;
fi;
od;
g:=Order((E(n)^m2)^a);
g1:=E(m1);
for m2 in [1..(a-1)] do
g1:=E(m1)*g1^b;
od;
g1:=Order(g1);
g2:=Order(E(m1)^c);
g3:=Lcm(g,g1);
if (g3/g2 in Integers) then
A1:=[A[1]*a,F];
fi;
fi;
return A1;
end);
#######################################################
# Finds group over which cyclotomic algebra of length 4 or 5
# is faithfully represented.
#######################################################
InstallGlobalFunction( DefiningGroupAndCharacterOfCyclotAlg, function(A)
local l,f,a,b,c,d,g,I,g1,S,m,n,i,chi,F,u,V,U,F1,k,gen,ord,hs,rs,ss,cs,relact,relpow,relcom,rel;
l:=Length(A);
if l=2 then
return fail;
fi;
########## DEALING WITH ARBITRARY NUMBER OF GENERATORS FOR THE GALOIS GROUP #####################
if l=5 then
k:=Length(A[4]);
f:=FreeGroup(k+1);
gen := GeneratorsOfGroup(f);
ord:=A[3];
hs:=List([1..k],x->A[4][x][1]);
rs:=List([1..k],x->A[4][x][2]);
ss:=List([1..k],x->A[4][x][3]);
cs := A[5];
relact := List([1..k], i -> (gen[1]^gen[i+1])*gen[1]^-rs[i]);
relpow := List([1..k], i -> (gen[i+1]^hs[i])*gen[1]^-ss[i]);
relcom := Concatenation(List([1..k-1], i -> List([1..k-i], j -> gen[i+j+1]^-1*gen[i+1]^-1*gen[i+j+1]*gen[i+1]*gen[1]^-cs[i][j])));
rel := Concatenation([gen[1]^ord],relact,relpow,relcom);
g := f/rel;
fi;
########## END OF DEALING WITH ARBITRARY NUMBER OF GENERATORS FOR THE GALOIS GROUP #####################
if (l=4) then
f:=FreeGroup("a","b");
a:=f.1;
b:=f.2;
g:=f/[a^A[3],b^A[4][1]*a^(-A[4][3]),b^(-1)*a*b*a^(-A[4][2])];
fi;
I:=IsomorphismSpecialPcGroup(g);
g1:=Image(I);
S:=[];
S[1]:=g1;
if Length(A)=2 then d:=1; fi;
if Length(A)=4 then d:=A[4][1]; F1:=NF(A[3],[A[4][2]]); fi;
if Length(A)=5 then
V:=[];
d:=1;
for i in [1..Length(A[4])] do Add(V,A[4][i][2]); od;
for i in [1..Length(A[4])] do d:=d*A[4][i][1]; od;
F1:=NF(A[3],V);
fi;
n:=Size(Irr(g1)) ;
m:=Trace(F1,Rationals,1);
U:=[];
for i in [1..n] do
chi:=Irr(g1)[n-i+1];
V:=ValuesOfClassFunction(chi);
F:=FieldByGenerators(V);
if IsPosInt(V[1]/d) then
if Size(KernelOfCharacter(chi))=1 then
if FieldByGenerators(V)=F1 then
Add(U,n-i+1);
fi;
fi;
fi;
od;
if Size(U)=m then
u:=U[1];
chi:=Irr(g1)[u];
else
chi:=U;
fi;
S[2]:=chi;
return S;
end);
#######################################################
InstallGlobalFunction( DefiningGroupOfCyclotomicAlgebra, function(A)
local l,f,a,b,c,d,g,I,g1,k,gen,ord,hs,rs,ss,cs,relact,relpow,relcom,rel;
l:=Length(A);
if l=2 then g1:=SmallGroup(1,1);
else
g1:="fail";
########## DEALING WITH ARBITRARY NUMBER OF GENERATORS FOR THE GALOIS GROUP #####################
if l=5 then
k:=Length(A[4]);
f:=FreeGroup(k+1);
gen := GeneratorsOfGroup(f);
ord:=A[3];
hs:=List([1..k],x->A[4][x][1]);
rs:=List([1..k],x->A[4][x][2]);
ss:=List([1..k],x->A[4][x][3]);
cs := A[5];
relact := List([1..k], i -> (gen[1]^gen[i+1])*gen[1]^-rs[i]);
relpow := List([1..k], i -> (gen[i+1]^hs[i])*gen[1]^-ss[i]);
relcom := Concatenation(List([1..k-1], i -> List([1..k-i], j -> gen[i+j+1]^-1*gen[i+1]^-1*gen[i+j+1]*gen[i+1]*gen[1]^-cs[i][j])));
rel := Concatenation([gen[1]^ord],relact,relpow,relcom);
g := f/rel;
fi;
########## END OF DEALING WITH ARBITRARY NUMBER OF GENERATORS FOR THE GALOIS GROUP #####################
if (l=4) then
f:=FreeGroup("a","b");
a:=f.1;
b:=f.2;
g:=f/[a^A[3],b^A[4][1]*a^(-A[4][3]),b^(-1)*a*b*a^(-A[4][2])];
fi;
I:=IsomorphismSpecialPcGroup(g);
g1:=Image(I);
fi;
return g1;
end);
#################################################
InstallGlobalFunction( DefiningCharacterOfCyclotomicAlgebra, function(A)
local g1,d,m,n,i,chi,F,u,V,U,F1;
if Length(A)=2 then u:=1; else
if Length(A)>2 then
g1:=DefiningGroupOfCyclotomicAlgebra(A);
if Length(A)=4 then
d:=A[4][1];
F1:=NF(A[3],[A[4][2]]);
fi;
if Length(A)=5 then
V:=[];
d:=1;
for i in [1..Length(A[4])] do Add(V,A[4][i][2]); od;
for i in [1..Length(A[4])] do d:=d*A[4][i][1]; od;
F1:=NF(A[3],V);
fi;
n:=Size(Irr(g1)) ;
m:=Trace(F1,Rationals,1);
U:=[];
for i in [1..n] do
chi:=Irr(g1)[n-i+1];
V:=ValuesOfClassFunction(chi);
F:=FieldByGenerators(V);
if IsPosInt(V[1]/d) then
if Size(KernelOfCharacter(chi))=1 then
if FieldByGenerators(V)=F1 then
Add(U,n-i+1);
fi;
fi;
fi;
od;
if Size(U)=m then
u:=U[1];
else
u:=U;
fi;
fi;
fi;
return u;
end);
##########################################
# The next function was created to replace SimpleAlgebraByCharacterInfo
# before it was fixed to work over larger fields.
##########################################
InstallGlobalFunction( SimpleComponentOfGroupRingByCharacter, function(F,G,n)
local R,chi,B;
R:=GroupRing(F,G);
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
chi:=Irr(G)[n];
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
chi:=n;
else
Error("The third argument must be a character or its number\n");
fi;
B:=SimpleAlgebraByCharacterInfo(R,chi);
return B;
end);
#######################################################
# Global Character Descent functions - this
# adds as much Clifford theory as is possible over
# the global field before local methods need to be
# used. This is needed because wedderga's local index
# functions are designed for crossed products that
# have been reduced in this way.
#######################################################
#######################################################
# These functions are intended to provide an enhancement
# to wedderga to extend its capabilities from small groups
# to some medium-sized groups. Given chi Irr(G)[n] and a
# cyclotomic field K, you want to determine the simple
# component of KG corresponding to chi. The algorithm
# initially searches the irreducible characters of
# maximal subgroups M for a constituent phi for which
# (chi_M, phi) is coprime to chi(1) and K(phi)=K, and
# when it finds such a pair (M,phi) it replaces (G,chi)
# with (M,phi) and repeats. This works because this
# condition implies the simple component of KM corresponding
# to phi is Brauer equivalent to the simple component of KG
# corresponding to chi. Once this process terminates it
# reverts to wedderga's functions for expressing the
# simple component.
#
# The main computational barrier to its effectiveness is
# for some larger groups have too many maximal subgroups.
# Since it must store them all one can get memory crashes.
# Another issue is that there are groups with characters
# have no global reduction with arbitrarily large size, or
# the algorithm terminates too quickly to a subgroup that
# is still too large for wedderga to handle. In these
# unlucky situations this algorithm will be a waste of time.
#
# For calculating the simple component of KG corresponding
# to chi = Irr(G)[n], the command is
#
# SimpleComponentByCharacterDescent(K,G,n);
#
# For the Wedderburn Decomposition of KG the command is
#
# WedderburnDecompositionByCharacterDescent(K,G);
#
# (note that this differs from other wedderga functions since
# the input here is not the group ring). This will perform
# the calculation one character at a time, its performance
# is only saved because the maximal subgroup lattice won't be
# recalculated each time.
################################################
InstallGlobalFunction( CharacterDescent, function(F,G,n,e,H)
local chi,M,m,r,y,U,F1,D,y1,i,psi,C,j,m1,F2,y2,chi1,k,n1;
chi:=Irr(G)[n];
m:=chi[1];
r:=1;
y:=PrimitiveElement(F);
F1:=Field(Concatenation(chi,[y]));
D:=[r,F1,G,n];
y1:=PrimitiveElement(F1);
psi:=RestrictedClassFunction(chi,H);
C:=ConstituentsOfCharacter(psi);
for j in [1..Size(C)] do
m1:=ScalarProduct(psi,C[j]);
if Gcd(m1,e)=1 then
F2:=Field(C[j]);
y2:=PrimitiveElement(F2);
if y2 in F1 then
for k in [1..Size(Irr(H))] do
if Irr(H)[k]=C[j] then
n1:=k;
r:=m/(ValuesOfClassFunction(C[j])[1]);
D:=[r,F1,H,k];
break;
fi;
od;
fi;
fi;
od;
return D;
end);
########################
InstallGlobalFunction( GlobalCharacterDescent, function(F,G,n)
local e,r,t,y,V,F1,R,M,m,n1,s,i,H,D;
e:=Size(G);
r:=1;
t:=0;
y:=PrimitiveElement(F);
V:=Concatenation(ValuesOfClassFunction(Irr(G)[n]),[y]);
F1:=Field(V);
R:=[r,F1,G,n];
n1:=Irr(G)[n][1];
if n1>1 then
while t=0 do
M:=ConjugacyClassesMaximalSubgroups(R[3]);
m:=Size(M);
i:=m;
for i in [1..m] do
H:=Representative(M[m-i+1]);
D:=CharacterDescent(F1,R[3],R[4],e,H);
if Size(D[3])<Size(R[3]) then
s:=n1/(Irr(D[3])[D[4]][1]);
R:=[r*s,F1,D[3],D[4]];
t:=1;
break;
fi;
od;
if i=m and t=0 then t:=1; fi;
od;
fi;
return R;
end);
########################################
InstallGlobalFunction( GaloisRepsOfCharacters, function(F1,G)
local U,U1,V,y,y1,T,n,k,i,j,i1,t,F,m;
U:=[1];
U1:=[];
y:=PrimitiveElement(F1);
T:=Irr(G);
n:=Size(Irr(G));
i:=1;
for i in [2..n] do
V:=ValuesOfClassFunction(T[i]);
F:=Field(V);
y1:=PrimitiveElement(F);
if y1 in F1 then
Add(U,i);
else
Add(U1,i);
fi;
od;
if not(U1=[]) then
Add(U,U1[1]);
for i in [2..Length(U1)] do
F:=Field(Union(ValuesOfClassFunction(T[U1[i]]),[y]));
k:=Conductor(F);
t:=1;
for j in [2..k-1] do
if Gcd(j,k)=1 then
if (GaloisCyc(y,j)=y) then
for i1 in [1..i-1] do
if GaloisCyc(ValuesOfClassFunction(T[U1[i1]]),j)=ValuesOfClassFunction(T[U1[i]]) then
t:=0;
break;
fi;
od;
fi;
fi;
od;
if t=1 then Add(U,U1[i]); fi;
od;
fi;
Sort(U);
return U;
end);
###########################
InstallGlobalFunction( SimpleComponentByCharacterDescent, function(F,G,n)
local R,n1,n2,r,S,S0,T;
n1:=Size(G);
R:=GlobalCharacterDescent(F,G,n);
n2:=Size(R[3]);
r:=R[1];
while n2<n1 do
n2:=Size(R[3]);
R:=GlobalCharacterDescent(R[2],R[3],R[4]);
n1:=Size(R[3]);
r:=r*R[1];
od;
T:=SimpleComponentOfGroupRingByCharacter(R[2],R[3],R[4]);
T[1]:=r*T[1];
T:=GlobalSplittingOfCyclotomicAlgebra(T);
return T;
end);
###########################
InstallGlobalFunction( WedderburnDecompositionByCharacterDescent, function(F,G)
local R,S,y,n,U,F1,T;
R:=[];
S:=GaloisRepsOfCharacters(F,G);
y:=PrimitiveElement(F);
for n in S do
U:=Union(ValuesOfClassFunction(Irr(G)[n]),[y]);
F1:=Field(U);
T:=SimpleComponentByCharacterDescent(F1,G,n);
Add(R,T);
od;
return R;
end);
######################
################################
# Given a simple component of a rational group algebra whose
# "WedderburnDecompositionInfo" output has 4 terms, the next
# three functions compute its indices at odd primes, infinity,
# and 2.
################################
InstallGlobalFunction( LocalIndexAtOddP, function(A,q)
local m,F,n,a,b,c,n1,e,f,h,f1,e1,k;
m:=1;
F:=A[2];
a:=A[4][1];
b:=A[4][2];
c:=A[4][3];
n:=Lcm(Conductor(F),A[3]);
n1:=PDashPartOfN(n,q);
e:=RamificationIndexAtP(F,n,q);
if e>1 and c>0 and IsPosInt(A[3]/q) then
f:=ResidueDegreeAtP(Rationals,n,q);
h:=ResidueDegreeAtP(F,n,q);
f1:=f/h;
e1:=Gcd(q^f1-1,e);
k:=(q^f1-1)/e1;
while not IsPosInt(k/(Order(E(A[3])^(c*m)))) do
m:=m+1;
od;
fi;
return m;
end);
###############################
# For the computation of the index of a cyclic
# cyclotomic algebra at infinity, we determine the
# nature of the algebra as a quadratic algebra
# over the reals.
###############################
InstallGlobalFunction( LocalIndexAtInfty, function(A)
local m,n,s,n1;
m:=1;
n:=A[3];
if n>2 then
s:=ANFAutomorphism(A[2],-1);
if s=ANFAutomorphism(A[2],1) then
if E(n)^A[4][3]=-1 then
m:=2;
fi;
fi;
fi;
return m;
end);
###############################
# For the local index at 2, we detect if the cyclic
# cyclotomic algebra will be of nonsplit quaternion type
# over the 2-adics
###############################
InstallGlobalFunction( LocalIndexAtTwo, function(A)
local n,m,a,K,b,c,f1,f,e1,e,h,g,n2,n3,n4,i,u,U,U1;
m:=1;
a:=A[4][1];
if IsPosInt(A[3]/4) and IsEvenInt(a) then
n:=Lcm(Conductor(A[2]),A[3]);
f1:=ResidueDegreeAtP(A[2],n,2);
f:=ResidueDegreeAtP(Rationals,n,2);
e1:=RamificationIndexAtP(A[2],n,2);
e:=RamificationIndexAtP(Rationals,n,2);
if IsOddInt(f/f1) and IsOddInt(e/e1) then
#K:=PSplitSubextension(A[2],n,2);
#if IsOddInt(Trace(K,A[2],1)) then
b:=A[4][2];
c:=A[4][3];
n2:=PPartOfN(n,2);
n4:=PPartOfN(A[3],2);
if E(n2)^b=E(n2)^(-1) and E(n4)^c=-1 then
m:=2;
fi;
fi;
fi;
return m;
end);
##############################
# Given a group G and a simple component A whose
# WedderburnDecompositionInfo in wedderga has length 4,
# this program gives the list of local indices at
# all primes relevant to the rational Schur index
###############################
InstallGlobalFunction( LocalIndicesOfCyclicCyclotomicAlgebra, function(A)
local n,S,s,i,L,l,q,L1;
L:=[];
if A[4][3]=0 then
L1:=[];
else
S:=AsSet(FactorsInt(A[3]));
s:=Size(S);
for i in [1..s] do
if S[i]=2 then
l:=LocalIndexAtTwo(A);
L[i]:=[];
L[i][1]:=2;
L[i][2]:=l;
else
q:=S[i];
l:=LocalIndexAtOddP(A,q);
L[i]:=[];
L[i][1]:=q;
L[i][2]:=l;
fi;
od;
l:=LocalIndexAtInfty(A);
L[s+1]:=[];
L[s+1][1]:= infinity;
L[s+1][2]:=l;
L1:=[];
s:=Size(L);
for i in [1..s] do
if L[i][2]>1 then
Add(L1,L[i]);
fi;
od;
fi;
return L1;
end);
##########################################
InstallGlobalFunction( IsDyadicSchurGroup, function(G)
local t,d,P,l,P1,l1,p1,i,Y,q,U,V,V1,L,P2,l2;
d:=false;
P:=SylowSubgroup(G,2);
#### Check that G = Q8 ######
if G=P then
if IdSmallGroup(G)=[8,4] then
d:=true;
fi;
fi;
#### Check G is semidirect product of C_q by P, q odd prime ####
if d=false then
q:=Size(G)/Size(P);
if IsPrimeInt(q) then
U:=SylowSubgroup(G,q);
V:=Centralizer(P,U);
if not(V=P) then
### Check if G is of type (Q8,q) ####
if IdSmallGroup(V)=[8,4] then
V1:=Centralizer(P,V);
L:=UnionSet(Elements(V),Elements(V1));
P2:=GroupByGenerators(L);
if P=P2 then
if PPartOfN(OrderMod(2,q),2)=Size(P/V) then
d:=true;
fi;
fi;
fi;
#### Check that P is a dyadic 2-group #####
if d=false then
t:=false;
l:=Size(P);
P1:=DerivedSubgroup(P);
l1:=Size(P1);
if l>l1 and IsInt(l1/4) and IsCyclic(P1) then
p1:=GeneratorsOfGroup(P1);
for i in [1..Length(p1)] do
if Order(p1[i])=l1 then
break;
fi;
od;
Y:=Centralizer(P,p1[i]^(l1/4));
if IsCyclic(Y/P1) then
t:=true;
fi;
if IdSmallGroup(V)=[8,4] then
if not(PPartOfN(OrderMod(2,q),2)>Size(P/V)) then
t:=false;
fi;
fi;
#### Check if G is of type (QD,q) ###
if t=true then
if not(IsAbelian(V)) then
l2:=Size(V);
if l2/l1=2 then
if not(PPartOfN(OrderMod(2,q),2)<Size(P/V)) then
d:=true;
fi;
fi;
fi;
fi;
####
fi;
fi;
fi;
####
fi;
fi;
return d;
end);
##########################################
InstallGlobalFunction( LocalIndexAtInftyByCharacter, function(F,G,n)
local m,T,v2,a,pos;
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
pos:=n;
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
pos := Position( Irr(G), n );
else
Error("The fourth argument must be a character or its number\n");
fi;
m:=1;
T:=CharacterTable(G);
v2:=Indicator(T,2)[pos];
a:=PrimitiveElement(F);
if GaloisCyc(a,-1)=a then
if v2=-1 then
m:=2;
fi;
fi;
return m;
end);
###########################################
InstallGlobalFunction( FinFieldExt, function(F,G,p,n,n1)
local chi,V,Y,h,a,m1,d1,L,i,z,l,m,K,B,d,M,C,D,b,j,F1,M1,M2,psi,U,k,F2,t;
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
chi:=Irr(G)[n];
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
chi:=n;
else
Error("The fourth argument must be a character or its number\n");
fi;
if IsPosInt(n1) then
if HasOrdinaryCharacterTable(G) and IsBound( ComputedBrauerTables( CharacterTable(G) )[p] ) then
psi:=Irr( BrauerTable(G,p) )[n1];
else
Error("The group has no Brauer character table for p=", p, " yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n1) and n1 in Irr( BrauerTable(G,p) ) then
psi:=n1;
else
Error("The fifth argument must be a Brauer character at ", p, " or its number\n");
fi;
V:=ValuesOfClassFunction(chi);
Y:=OrdersClassRepresentatives( CharacterTable(G) );
h:=Size(Y);
a:=PrimitiveElement(F);
m1:=PDashPartOfN(Conductor(a),p);
for i in [1..m1] do if (m1=1 or PowerMod(p,i,m1)=1) then d1:=i; break; fi; od;
L:=[];
for i in [1..h] do if Gcd(Y[i],p) = 1 then Add(L,V[i]); fi; od;
l:=Size(L);
m:=Conductor(L);
K:=CF(m);
B:=Basis(K);
for i in [1..m] do if (m=1 or PowerMod(p,i,m)=1) then d:=i; break; fi; od;
z:=Z(p^d)^((p^d-1)/m);
M:=[];
D:=[];
for i in [1..Size(B)] do
for j in [1..m] do
if B[i]=E(m)^j then
D[i]:=j;
fi;
od;
od;
for i in [1..l] do
C:=Coefficients(B,L[i]);
b:=0;
for j in [1..Size(B)] do
b:=b+C[j]*z^(D[j]);
od;
M[i]:=b;
od;
M1:=UnionSet(M,[Z(p^d1)]);
F1:=FieldByGenerators(M1);
U:=ValuesOfClassFunction(psi);
m:=Conductor(U);
K:=CF(m);
B:=Basis(K);
for i in [1..m] do if (m=1 or PowerMod(p,i,m)=1) then d:=i; break; fi; od;
z:=Z(p^d)^((p^d-1)/m);
M:=[];
D:=[];
for i in [1..Size(B)] do
for j in [1..m] do
if B[i]=E(m)^j then
D[i]:=j;
break;
fi;
od;
od;
for i in [1..l] do
C:=Coefficients(B,U[i]);
b:=0;
for j in [1..Size(B)] do
b:=b+C[j]*z^(D[j]);
od;
M[i]:=b;
od;
M2:=UnionSet(M,M1);
F2:=FieldByGenerators(M2);
t:=LogInt(Size(F2),Size(F1));
return t;
end);
##############################################
# Oct 2014 New Defect Group Functions
##############################################
InstallGlobalFunction( DefectGroupOfConjugacyClassAtP, function(G,c,p)
local C,g1,H,D;
C:=ConjugacyClasses(G);
g1:=Representative(C[c]);
H:=Centralizer(G,g1);
D:=SylowSubgroup(H,p);
return D;
end);
#############################
InstallGlobalFunction( DefectGroupsOfPBlock, function(G,n,p)
local D1,D2,r,U,U1,T,chi,C,c,i,m,h1,a1,a2,b1,A1,D;
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
chi:=Irr(G)[n];
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
chi:=n;
else
Error("The third argument must be a character or its number\n");
fi;
T:=CharacterTable(G);
C:=ConjugacyClasses(G);
c:=Size(C);
U:=[];
U1:=[];
for i in [1..c] do
m:=OrdersClassRepresentatives(T)[i];
if not(m mod p = 0 mod p) then
AddSet(U,i);
AddSet(U1,i);
fi;
od;
for i in U1 do
h1:=Size(C[i]);
a1:=chi[i];
b1:=chi[1];
A1:=(h1*a1)/b1;
r:=PDashPartOfN(Size(G),p);
a2:=Norm(r*A1);
if not(a2 in Integers) or (a2/p in Integers) then
RemoveSet(U,i);
fi;
od;
D2:=[];
for i in U do
D:=DefectGroupOfConjugacyClassAtP(G,i,p);
AddSet(D2,D);
od;
if Length(D2)>1 then
D1:=D2[1];
for i in [2..Size(D2)] do
if Size(D2[i])<Size(D1) then
D1:=D2[i];
fi;
od;
else
D1:=D2[1];
fi;
D:=ConjugacyClassSubgroups(G,D1);
return D;
end);
####################
InstallGlobalFunction( DefectOfCharacterAtP, function(G,n,p)
local D1,D,q,d;
D1:=DefectGroupsOfPBlock(G,n,p);
D:=Representative(D1);
q:=Size(D);
d:=LogInt(q,p);
return d;
end);
##########################################
InstallGlobalFunction( LocalIndexAtPByBrauerCharacter, function(F,G,n,p)
local chi,n1,V,a,V1,C,m1,b,j,k,u,t,T,S,U,f,m2,n0,K0,d0,F1,K1,d1;
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
chi:=Irr(G)[n];
n1:=n;
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
chi:=n;
n1:=Position(Irr(G),chi);
else
Error("The third argument must be a character or its number\n");
fi;
V:=ValuesOfClassFunction(chi);
a:=PrimitiveElement(F);
V1:=Union(V,[a]);
F1:=FieldByGenerators(V1);
C:=FieldByGenerators(V);
m1:=[];
m1[1]:=1;
m1[2]:="DGisCyclic";
T:=CharacterTable(G);
S:=T mod p;
b:=BlocksInfo(S);
for j in [1..Size(b)] do
if n1 in b[j].ordchars then
k:=b[j].modchars[1];
break;
fi;
od;
#####################
# Adapted to new defect group function
#####################
U:=DefectGroupsOfPBlock(G,n,p);
if not(IsCyclic(Representative(U))) then
m1[2]:="DGnotCyclic";
fi;
####################################
t:=FinFieldExt(C,G,p,n,k);
if t>1 then
m1[1]:=t;
fi;
m2:=m1;
if m2[2]="DGisCyclic" then
m1:=m2[1];
a:=PrimitiveElement(F);
V1:=Union(V,[a]);
n0:=Conductor(V1);
K0:=PSplitSubextension(C,n0,p);
d0:=Trace(CF(n0),K0,1);
F1:=FieldByGenerators(V1);
K1:=PSplitSubextension(F1,n0,p);
d1:=Trace(CF(n0),K1,1);
m1:=m1/Gcd(m1,d0/d1);
fi;
return m1;
end);
###########################################
InstallGlobalFunction( LocalIndexAtOddPByCharacter, function(F,G,n,p)
local m,B,K,B1,g,n1;
m:=1;
B:=SimpleComponentOfGroupRingByCharacter(F,G,n);
if Length(B)=2 then
m:=1;
fi;
if Length(B)=4 then
m:=LocalIndexAtOddP(B,p);
fi;
if Length(B)=5 then
K:=PSplitSubextension(F,B[3],p);
B1:=SimpleComponentOfGroupRingByCharacter(K,G,n);
g:=DefiningGroupAndCharacterOfCyclotAlg(B1);
if g=fail then
m:=1;
else
m:=LocalIndexAtPByBrauerCharacter(K,g[1],g[2],p);
fi;
fi;
return m;
end);
###########################################
InstallGlobalFunction( LocalIndexAtTwoByCharacter, function(F,G,n)
local m,chi,g,g1,B1,W,i,a,B,K,V,V1,a1,F0,F1,n0,n1,n01,n02,n11,n12,f,f0,f1,m2;
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
chi:=Irr(G)[n];
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
chi:=n;
else
Error("The third argument must be a character or its number\n");
fi;
m2:=1;
m:=0;
B:=SimpleComponentOfGroupRingByCharacter(F,G,n);
if Length(B)=2 then
m2:=1;
fi;
if Length(B)=4 then
m2:=LocalIndexAtTwo(B);
fi;
if Length(B)=5 then
K:=PSplitSubextension(F,B[3],2);
B1:=SimpleComponentOfGroupRingByCharacter(K,G,n);
if Length(B1)<5 then
if Length(B1)=2 then m2:=1; fi;
if Length(B1)=4 then m2:=LocalIndexAtTwo(B1); fi;
else
g:=DefiningGroupAndCharacterOfCyclotAlg(B1);
if g=fail then
m2:=1;
else
m2:=LocalIndexAtPByBrauerCharacter(K,g[1],g[2],2);
fi;
if not(m2 in Integers) then
m:=1;
if IsDyadicSchurGroup(g[1]) then
m:=2;
V:=ValuesOfClassFunction(chi);
F0:=FieldByGenerators(V);
F1:=B1[2];
if not(F0=F1) then
if E(4) in F1 then
m:=1;
else
n0:=Conductor(F0);
n02:=PPartOfN(n0,2);
n1:=Conductor(F1);
n12:=PPartOfN(n1,2);
if not(n02=n12) then
m:=1;
else
n11:=PDashPartOfN(n1,2);
f1:=OrderMod(2,n1);
n01:=PDashPartOfN(n0,2);
f0:=OrderMod(2,n0);
f:=f1/f0;
if IsPosInt(f/2) then
m:=1;
fi;
fi;
fi;
fi;
fi;
fi;
fi;
fi;
if m>0 then m2:=m; fi;
return m2;
end);
#############################################
InstallGlobalFunction( LocalIndicesOfCyclotomicAlgebra, function(A)
local L,F,l,d,G,n,m0,m2,m,P,p,l1,l2,i,L1;
##################
# bugfix lines (20/03/2020)
##################
A:=GlobalSplittingOfCyclotomicAlgebra(A);
l:=Length(A);
if l>4 then
l2:=Length(A[4]);
l1:=l2-1;
l:=Length(A);
while l>4 and l1<l2 do
l2:=Length(A[4]);
G:=DefiningGroupOfCyclotomicAlgebra(A);
n:=DefiningCharacterOfCyclotomicAlgebra(A);
A:=SimpleComponentByCharacterDescent(A[2],G,n);
l:=Length(A);
if l>4 then l1:=Length(A[4]); fi;
od;
fi;
##################
L:=[];
L1:=[];
F:=A[2];
l:=Length(A);
if l=5 then
d:=DefiningGroupAndCharacterOfCyclotAlg(A);
G:=d[1];
n:=d[2];
m0:=LocalIndexAtInftyByCharacter(F,G,n);
Add(L1,[infinity,m0]);
P:=AsSet(Factors(Size(G)));
if P[1]=2 then
m2:=LocalIndexAtTwoByCharacter(F,G,n);
Add(L1,[2,m2]);
fi;
P:=Difference(P,[2]);
if Size(P)>0 then
for i in [1..Size(P)] do
p:=P[i];
m:=LocalIndexAtOddPByCharacter(F,G,n,p);
Add(L1,[p,m]);
od;
fi;
l1:=Size(L1);
for i in [1..l1] do
if not(L1[i][2]=1) then
Add(L,L1[i]);
fi;
od;
fi;
if (l=4 and not(A[4][3]=0)) then
L:=LocalIndicesOfCyclicCyclotomicAlgebra(A);
fi;
return L;
end);
############################################
InstallGlobalFunction( RootOfDimensionOfCyclotomicAlgebra, function(A)
local d,i;
if Length(A)<4 then
d:=A[1];
fi;
if Length(A)=4 then
d:=A[1]*A[4][1];
fi;
if Length(A)=5 then
d:=A[1];
for i in [1..Length(A[4])] do
d:=d*A[4][i][1];
od;
fi;
return d;
end);
###########################################
# Calculates the least common multiple of the list of
# local indices
###########################################
InstallGlobalFunction( GlobalSchurIndexFromLocalIndices, function(L)
local l,m,i;
l:=Length(L);
m:=1;
if l>0 then
m:=L[1][2];
fi;
if l>1 then
for i in [2..l] do
m:=Lcm(m,L[i][2]);
od;
fi;
return m;
end);
###########################################
InstallGlobalFunction( CyclotomicAlgebraWithDivAlgPart, function(A)
local L,m,d,B,D;
L:=LocalIndicesOfCyclotomicAlgebra(A);
m:=GlobalSchurIndexFromLocalIndices(L);
d:=RootOfDimensionOfCyclotomicAlgebra(A);
if m>1 then
D:=rec(DivAlg:=true, Center:=A[2], SchurIndex:=m, LocalIndices:=L);
B:=[d/m,D];
else
B:=[d,A[2]];
fi;
return B;
end);
###############################################
# Main function for obtaining the Wedderburn decomposition
# for R = GroupRing(F,G) with division algebra parts identified
# in terms of local indices
###############################################
InstallGlobalFunction( WedderburnDecompositionWithDivAlgParts, function(R)
local W,w,i,W1;
W:=WedderburnDecompositionInfo(R);
w:=Size(W);
W1:=[];
for i in [1..w] do
if Length(W[i]) < 4 then
Add(W1,W[i]);
else
W1[i]:=CyclotomicAlgebraWithDivAlgPart(W[i]);
fi;
od;
return W1;
end);
#############################
# Given a Schur algebra output from "wedderga" with 5 terms
# that decomposes as the tensor product of two generalized
# quaternion algebras, the first function determines this
# tensor decomposition.
# #############################
InstallGlobalFunction( DecomposeCyclotomicAlgebra, function(A)
local B,B1,m1,n,m,d,c,z,r,s,t,u,v,u1,i,j,b,F,w,A1,V,y,y1,y2,y3,y31,y32,F1,F2,F3,k,c1;
if not(Length(A)>2) then return fail; fi;
if Length(A)=4 then
F:=A[2];
m:=A[3];
c:=A[4][3];
y:=PrimitiveElement(F);
F1:=Field([y,E(m)]);
d:=E(m)^c;
B:=[F,F1,[d]];
return B;
fi;
if Length(A)=5 then
A1:=KillingCocycle(A);
B:=[];
k:=Length(A1[4]);
if ForAll(A1[5],x->ForAll(x,y->y=0)) then
F:=A1[2];
y:=PrimitiveElement(F);
m:=A1[3];
F1:=Field([y,E(m)]);
c:=Conductor(F1);
for i in [1..k] do
V:=[];
for j in [1..k] do
if i<>j then Add(V,A1[4][j][2]); fi;
od;
F2:=NF(m,V);
c:=PrimitiveElement(F2);
F1:=Field([y,c]);
c1:=E(m)^A1[4][i][3];
Add(B,[F,F1,[c1]]);
od;
fi;
if Length(B)=k then return B; fi;
fi;
if Length(A1)=5 and B=[] then
n:=A1[3];
F:=A1[2];
y:=PrimitiveElement(F);
c:=Conductor(Field([y,E(n)]));
if Length(A1)=5 and Length(A1[4])=2 then
if not(A1[5][1][1]=0) then
d:=A1[5][1][1];
z:=E(n)^d;
y1:=PrimitiveElement(NF(n,[A[4][2][2]]));
y2:=PrimitiveElement(NF(n,[A[4][1][2]]));
F1:=Field([y,y1]);
F2:=Field([y,y2]);
F3:=Field([y,y1,y2]);
y3:=PrimitiveElement(F3);
m1:=0;
while E(2^(m1+1)) in F3 do m1:=m1+1; od;
y31:=Trace(F3,F2,E(2^m1));
y32:=Trace(F3,F1,E(2^m1));
for i in [1..2^m1-1] do
if B=[] and GaloisCyc(E(2^m1)^i*z,A1[4][1][2])=E(2^m1)^i then
B[1]:=[F,F1,[E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[Norm(F3,F1,E(2^m1)^i)*E(n)^A1[4][2][3]]];
fi;
if B=[] and GaloisCyc(E(2^m1)^i,A1[4][2][2])*z=E(2^m1)^i then
B[1]:=[F,F1,[Norm(F3,F2,E(2^m1)^i)*E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[E(n)^A1[4][2][3]]];
fi;
if B=[] and GaloisCyc((1-E(2^m1)^i)*z,A1[4][1][2])=(1-E(2^m1)^i) then
B[1]:=[F,F1,[E(n)^A1[4][1][3]] ];
B[2]:=[F,F2,[Norm(F3,F1,(1-E(2^m1)^i))*E(n)^A1[4][2][3]]];
fi;
if B=[] and not(E(2^m1)^i=-1) and GaloisCyc((1+E(2^m1)^i)*z,A1[4][1][2])=(1+E(2^m1)^i) then
B[1]:=[F,F1,[E(n)^A1[4][1][3]] ];
B[2]:=[F,F2,[Norm(F3,F1,(1+E(2^m1)^i))*E(n)^A1[4][2][3]]];
fi;
if B=[] and not(E(2^m1)^i=-1) and GaloisCyc(1+E(2^m1)^i,A1[4][2][2])*z=(1+E(2^m1)^i) then
B[1]:=[F,F1,[Norm(F3,F2,(1+E(2^m1)^i))*E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[ E(n)^A1[4][2][3]] ];
fi;
if B=[] and GaloisCyc(1-E(2^m1)^i,A1[4][2][2])*z=(1-E(2^m1)^i) then
B[1]:=[F,F1,[Norm(F3,F2,(1-E(2^m1)^i))*E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[ E(n)^A1[4][2][3]] ];
fi;
od;
if B=[] then
t:=0;
for i in [1..n-1] do
for j in [1..n-1] do
if E(n)^j<>-E(n)^i and z*GaloisCyc(E(n)^i+E(n)^j,A[4][2][2])=E(n)^i+E(n)^j then t:=1; fi;
if t=1 then break; fi;
od;
if t=1 then break; fi;
od;
if t=1 then
B[1]:=[F,F1,[Norm(F3,F2,E(n)^i+E(n)^j)*E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[E(n)^A1[4][2][3]]];
fi;
fi;
if B=[] then
t:=0;
for i in [1..n-1] do
for j in [1..n-1] do
if E(n)^j<>-E(n)^i and GaloisCyc(z*(E(n)^i+E(n)^j),A[4][1][2])=E(n)^i+E(n)^j then t:=1; fi;
if t=1 then break; fi;
od;
if t=1 then break; fi;
od;
if t=1 then
B[1]:=[F,F1,[E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[Norm(F3,F1,E(n)^i+E(n)^j)*E(n)^A1[4][2][3]]];
fi;
fi;
if GaloisCyc(y3*z,A1[4][1][2])=y3 then
B[1]:=[F,F1,[E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[Norm(F3,F1,y3)*E(n)^A1[4][2][3]]];
fi;
if B=[] and GaloisCyc(y3,A[4][2][2])*z=y3 then
B[1]:=[F,F1,[Norm(F3,F2,y3)*E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[E(n)^A1[4][2][3]]];
fi;
if GaloisCyc(y31*z,A1[4][1][2])=y31 and y31<>0 then
B[1]:=[F,F1,[E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[Norm(F3,F1,y31)*E(n)^A1[4][2][3]]];
fi;
if B=[] and GaloisCyc(y32,A[4][2][2])*z=y32 and y32<>0 then
B[1]:=[F,F1,[Norm(F3,F2,y32)*E(n)^A1[4][1][3]]];
B[2]:=[F,F2,[E(n)^A1[4][2][3]]];
fi;
fi;
fi;
if B=[] then return fail; fi;
fi;
return B;
end);
################################################
# The next few functions allow conversions between
# cyclic algebras and quaternion algebras.
########################################################
InstallGlobalFunction( ConvertQuadraticAlgToQuaternionAlg, function(A)
local d,t,n,i,B;
n:=Conductor(A[2]);
i:=0;
t:=Trace(A[2],A[1],1);
if t=2 then
for d in [1..n] do
if Sqrt(d) in A[2] and not(Sqrt(d) in A[1]) then
i:=d;
break;
fi;
if Sqrt(-d) in A[2] and not(Sqrt(-d) in A[1]) then
i:=-d;
break;
fi;
od;
fi;
if not(i=0) then
B:=QuaternionAlgebra(A[1],i,A[3][1]);
else
B:="fail";
fi;
return B;
end);
#####################################################
InstallGlobalFunction( ConvertCyclicCyclotomicAlgToCyclicAlg, function(A)
local n,a,K,B;
if Length(A)=4 then
n:=A[3];
a:=PrimitiveElement(A[2]);
K:=FieldByGenerators([a,E(n)]);
B:=[A[2],K,[E(n)^A[4][3]]];
else
B:="fail";
fi;
return [A[1],B];
end);
###############################################
InstallGlobalFunction( ConvertCyclicAlgToCyclicCyclotomicAlg, function(A)
local F,K,n,i,j,M,k,l,m,B;
F:=A[1];
K:=A[2];
B:="fails";
if IsCyclotomicField(K) then
n:=Conductor(K);
if IsOddInt(n) then n:=2*n; fi;
if A[3][1]^n=1 then
k:=0;
for i in [1..n-1] do
if Gcd(i,n) = 1 then
m:=OrderMod(n,i);
M:=[];
for j in [1..m] do
AddSet(M,i^j mod n);
od;
if F=NF(n,M) then k:=i; break; fi;
fi;
od;
if k>0 then
m:=Order(ANFAutomorphism(K,k));
for i in [0..n] do
if E(n)^i=A[3][1] then l:=i; break; fi;
od;
B:=[1,F,n,[m,k,l]];
fi;
fi;
fi;
return B;
end);
#####################################################
#################################################
InstallGlobalFunction( ConvertQuaternionAlgToQuadraticAlg, function(A)
local F,K,B,b,d,d1,i,a;
d:=[];
b:=Elements(Basis(A));
for i in [1..4] do
if b[i]=Identity(A) then
d[i]:=0;
else
d[i]:=Sum(Coefficients(Basis(A),b[i]^2));
fi;
od;
d1:=[];
for i in [1..4] do
if not(d[i]=0) then
Add(d1,d[i]);
fi;
od;
Sort(d1);
F:=LeftActingDomain(A);
a:=PrimitiveElement(F);
if not(d1[1]+d1[3]<0) then
K:=FieldByGenerators([a,Sqrt(d1[1])]);
B:=[F,K,[d1[2]]];
else
if d1[3]<0 then
K:=FieldByGenerators([a,Sqrt(d1[2])]);
B:=[F,K,[d1[3]]];
else
K:=FieldByGenerators([a,Sqrt(d1[3])]);
B:=[F,K,[d1[2]]];
fi;
fi;
return B;
end);
##########################################
# The next few functions allow one to compute the
# local indices of rational quaternion algebras,
# and determine if it is a division algebra.
# The first one computes the local index of the
# symbol algebra (p,q) over Q when p and q are -1
# or a prime. Warning: It will not work when p or
# q are other integers, and it does not check this fact.
##########################################
InstallGlobalFunction( LocalIndicesOfRationalSymbolAlgebra, function(a,b)
local p,q,L,t;
L:=[];
if a < b then
p:=b;
q:=a;
else
p:=a;
q:=b;
fi;
if not(ForAll([p,q],t -> t=-1 or (IsPosInt(t) and IsPrimeInt(t)))) then
return fail;
fi;
if p=-1 then
L:=[[infinity,2],[2,2]];
elif p=2 then
L:=[];
elif p>2 then
if q=-1 then
if Legendre(q,p)=-1 then
L:=[[2,2],[p,2]];
else
L:=[];
fi;
elif q=2 then
if Legendre(2,p)=-1 then
L:=[[2,2],[p,2]];
else
L:=[];
fi;
elif p>q and q>2 then
if Legendre(q,p)=-1 then
if Legendre(p,q)=-1 then
L:=[[q,2],[p,2]];
else
L:=[[2,2],[p,2]];
fi;
else
if Legendre(p,q)=-1 then
L:=[[2,2],[q,2]];
fi;
fi;
elif p=q then
if Legendre(-1,p)=-1 then
L:=[[2,2],[p,2]];
fi;
fi;
fi;
return L;
end);
##################################################
InstallGlobalFunction( LocalIndicesOfTensorProductOfQuadraticAlgs, function(L,M)
local i,j,m,S,L1;
S:=[];
L1:=[];
if L=[] then L1:=M; else if M=[] then L1:=L;
else
for i in [1..Length(L)] do
AddSet(S,L[i][1]);
od;
for j in [1..Length(M)] do
AddSet(S,M[j][1]);
od;
for i in [1..Length(S)] do
m:=1;
for j in [1..Length(L)] do
if L[j][1]=S[i] then
m:=(m+2) mod 4;
fi;
od;
for j in [1..Length(M)] do
if M[j][1]=S[i] then
m:=(m+2) mod 4;
fi;
od;
if m>1 then
Add(L1,[S[i],2]);
fi;
od;
fi;
fi;
return L1;
end);
##########################################
# The next function computes local indices for
# quaternion algebras over the rationals. For
# quaternion algebras over larger number fields,
# we convert to quadratic algebras and use the
# cyclotomic algebra functions.
############################################
InstallGlobalFunction( LocalIndicesOfRationalQuaternionAlgebra, function(A)
local b,D1,D2,p,i,j,M,F,F1,L;
L:=fail;
if LeftActingDomain(A)=Rationals then
D1:=[];
D2:=[];
b:=Elements(Basis(A));
p:=Sum(Coefficients(Basis(A),b[3]^2));
F:=Factors(p);
for i in [1..Size(F)] do
if (p/(F[i]^2) in Integers) then
p:=p/F[i]^2;
fi;
od;
F:=Factors(p);
for i in [1..Size(F)] do
if F[i]<0 then
AddSet(D1,-1);
AddSet(D1,-F[i]);
else
AddSet(D1,F[i]);
fi;
od;
p:=Sum(Coefficients(Basis(A),b[2]^2));
F:=Factors(p);
for i in [1..Size(F)] do
if (p/(F[i]^2) in Integers) then
p:=p/F[i]^2;
fi;
od;
F:=Factors(p);
for i in [1..Size(F)] do
if F[i]<0 then
AddSet(D2,-1);
AddSet(D2,-F[i]);
else
AddSet(D2,F[i]);
fi;
od;
L:=[];
for i in [1..Size(D1)] do
for j in [1..Size(D2)] do
M:=LocalIndicesOfRationalSymbolAlgebra(D1[i],D2[j]);
L:=LocalIndicesOfTensorProductOfQuadraticAlgs(L,M);
od;
od;
fi;
return L;
end);
##############################################
# The next function checks if a Rational Quaternion Algebra
# is a division ring.
##############################################
InstallGlobalFunction( IsRationalQuaternionAlgebraADivisionRing, function(A)
local L,V;
L:=LocalIndicesOfRationalQuaternionAlgebra(A);
if L=[] then
V:=false;
else
V:=true;
fi;
return V;
end);
#################################################
InstallGlobalFunction( SchurIndex, function(A)
local m,i,l,L,B,C,D;
m:="fail: Unrecognized Algebra";
if IsAlgebra(A) then
if IsQuaternionCollection(Basis(A)) then
if LeftActingDomain(A)=Rationals then
L:=LocalIndicesOfRationalQuaternionAlgebra(A);
l:=Length(L);
m:=1;
if l>0 then
m:=L[1][2];
fi;
if l>1 then
for i in [2..l] do
m:=Lcm(m,L[i][2]);
od;
fi;
fi;
else
m:="fail: Quaternion Algebra Over NonRational Field, use another method.";
fi;
fi;
if IsRecord(A) then
m:=A.SchurIndex;
fi;
if IsList(A) then
l:=Length(A);
if Length(A)=2 and IsField(A[2]) then
m:=1;
fi;
if Length(A)=2 and IsRecord(A[2]) then
m:=A[2].SchurIndex;
fi;
if Length(A)=3 and IsField(A[1]) and IsField(A[2]) then
m:="fail: Cyclic Algebra, use another method.";
fi;
if Length(A)=4 then
L:=LocalIndicesOfCyclicCyclotomicAlgebra(A);
m:=GlobalSchurIndexFromLocalIndices(L);
fi;
if Length(A)=5 then
L:=LocalIndicesOfCyclotomicAlgebra(A);
m:=GlobalSchurIndexFromLocalIndices(L);
fi;
fi;
return m;
end);
############################################
InstallGlobalFunction( SchurIndexByCharacter, function(F,G,n)
local m,A,B,n1;
B:=Irr(G);
if IsPosInt(n) then
n1:=n;
else
if IsCharacter(n) then
n1:=Position(Irr(G),n);
fi;
fi;
A:=SimpleComponentByCharacterDescent(F,G,n1);
m:=SchurIndex(A);
return m;
end);
#############################################
InstallGlobalFunction( SimpleComponentByCharacterAsSCAlgebra, function(F,G,n)
local chi,F0,y0,y,F1,I,g,a,A;
if IsPosInt(n) then
if HasOrdinaryCharacterTable(G) then
chi:=Irr(G)[n];
else
Error("The group has no ordinary character table yet. To avoid randomisation errors, you should compute it first\n");
fi;
elif IsCharacter(n) then
chi:=n;
else
Error("The third argument must be a character or its number\n");
fi;
F0:=Field(chi);
y0:=PrimitiveElement(F0);
y:=PrimitiveElement(F);
F1:=Field([y,y0]);
I:=IrreducibleRepresentationsDixon(G,chi);
g:=Image(I);
a:=Algebra(F1,GeneratorsOfGroup(g));
A:=Image(IsomorphismSCAlgebra(a));
return A;
end);
############################
InstallGlobalFunction( CyclotomicAlgebraAsSCAlgebra, function(A)
local g,m,F,a;
g:=DefiningGroupAndCharacterOfCyclotAlg(A);
F:=A[2];
a:=SimpleComponentByCharacterAsSCAlgebra(F,g[1],g[2]);
return a;
end);
###########################
InstallGlobalFunction( WedderburnDecompositionAsSCAlgebras, function(R)
local W,l,W1,A,i;
W:=WedderburnDecompositionInfo(R);
l:=Size(W);
W1:=[];
for i in [1..l] do
if Size(W[i])=2 then
if W[i][1]=1 then
W1[i]:=W[i][2];
else
W1[i]:=MatrixAlgebra(W[i][2],W[i][1]);
fi;
fi;
if Size(W[i])>2 then
if W[i][1]=1 then
W1[i]:=CyclotomicAlgebraAsSCAlgebra(W[i]);
else
A:=CyclotomicAlgebraAsSCAlgebra(W[i]);
W1[i]:=MatrixAlgebra(A,W[i][1]);
fi;
fi;
od;
return W1;
end);
##########################
################################################
# AntiSymMatUpMat is a technical function which outputs an
# antisymmetric with input matrix from its upper
# triangular part.
# The input is given by a list of list of decreasing length
################################################
InstallGlobalFunction( AntiSymMatUpMat, function(x)
local k,y,i;
k := Length(x)+1;
y:=List([1..k],i->[]);
for i in [1..k-1] do
y[i] := Concatenation(List([1..i-1], j -> -x[j,i-j]),[0],x[i]);
od;
y[k] := Concatenation(List([1..k-1], j -> -x[j,k-j]),[0]);
return y;
end);
################################################
# KillingCocycle outputs the numerical information
# describing a cyclotomic algebra, equivalent to the input
# which is also the numerical information of a cyclotomic
# algebra, trying to put as zeroes in the fifth entry as possible.
################################################
InstallGlobalFunction( KillingCocycle, function(A)
local n,F,m,hrs,k,c,d,e,i,h,r,s,md,x,a,as,j,r1;
if Length(A) < 5 then
return A;
fi;
n := A[1];
F := A[2];
m := A[3];
hrs := List(A[4],x->List(x,y->y));
k := Length(hrs);
c := List(A[5],x->List(x,y->y));
e := AntiSymMatUpMat(c);
for i in [1..k] do
h:=hrs[i][1];
r:=hrs[i][2];
s:=hrs[i][3];
if r mod m <> 1 then
x:=Filtered([1..k],j-> e[i,j] mod Gcd(m,hrs[j][2]-1) = 0);
if Length(x) > 0 then
as:=[];
for j in Difference([1..k],[i]) do
r1 := hrs[j][2];
d := Gcd(m,r1-1);
md := m/d;
if j in x then
a := Int(ZmodnZObj(e[i,j]/d,md)*ZmodnZObj((r1-1)/d,md)^-1 );
else
a := 0;
fi;
Add(as,List([0..d-1],y->(a+y*md) mod m));
od;
as:=Intersection(as);
if Size(as)>1 then
a:=as[1];
hrs[i][3]:=(s+a*(r^h-1)/(r-1)) mod m;
for j in Difference(x,[i]) do
if j>i then
c[i][j-i]:=0;
else
c[j][i-j]:=0;
fi;
od;
e := AntiSymMatUpMat(c);
fi;
fi;
fi;
od;
return [n,F,m,hrs,c];
end);
################################################
# CyclotomicExtensionGenerator checks whether the input are two number fields
# and the first is a cyclotomic extension of the second
################################################
InstallGlobalFunction( CyclotomicExtensionGenerator, function(K,F)
local c,pr,e;
if not IsAbelianNumberField(K) or not IsAbelianNumberField(F) or not IsSubset(K,F) then
return 0;
fi;
c:=Lcm(2,Conductor(K));
e:=E(c);
while not e in K do
e:=e*E(c);
od;
pr := PrimitiveElement(F);
if Field([pr,e])=K then
return Order(e);
else
return 0;
fi;
end);
################################################
# ReducingCyclotomicAlgebra TRIES TO REDUCE THE NUMBER OF GENERATORS
################################################
InstallGlobalFunction( ReducingCyclotomicAlgebra, function(A)
local m,e,F,pF,K,gal,con,Ucon,k,acA,acon,i,x,y,F1,F2,c1,c2,c,g,h,n,act,coc1,coc2,l,pos,ex,a,j,A1,split,v,w,d1,cls,gcls,lc,A2,s1,s2;
if Length(A) < 5 then
return fail;
fi;
m:=A[3];
e := AntiSymMatUpMat(A[5]);
F:=A[2];
pF := PrimitiveElement(F);
K := Field([pF,E(m)]);
gal := GaloisGroup(AsField(F,K));
con := Lcm(2,Conductor(K));
Ucon := List(Units(ZmodnZ(con)),Int);
k := Length(A[4]);
acA := List([1..k],i->Filtered(gal,x->E(m)^x=E(m)^A[4][i][2])[1]);
acon := List(acA,x->Filtered(Ucon,i->E(con)^i=E(con)^x)[1]);
for x in [1..k] do
F2:=NF(con,[acon[x]]);
c2:=CyclotomicExtensionGenerator(F2,F);
if ForAll([1..k],j->e[x][j]=0) and c2<>0 then
y := Difference([1..k],[x]);
F1:=NF(con,List(y,j->acon[j]));
## A is a tensor product of a cyclic algebra A1=(F1/F,a1) and a cyclotomic algebra A2=F2*H.
## We check whether a1 is the norm of a root of unity in F, so that A1 is split.
c1 := Lcm(2,Conductor(F1));
g := E(c1);
while not g in F1 do
g:=g*E(c1);
od;
split := IsInt(Order(Norm(F1,F,g))*Gcd(m,A[4][x][3])/m);
h := E(m)^A[4][x][3];
## If not we check whether A1 is cyclotomic and in that case
## we check whether A1 it is split by verifying if its Schur index is 1
if not split and F1=Field([g,pF]) then
a := 1;
ex := 0;
for i in [0..c1-1] do
if a = h then
break;
else
ex:=ex+1;
a:=a*g;
fi;
od;
A1 := [1,F,c1,[A[4][x][1],acon[x] mod c1,ex]];
split := SchurIndex(A1)=1;
fi;
if split then
g:=E(c2);
act := [];
l := Length(y);
pos := 1;
if l>1 then
coc1 := [];
fi;
for i in y do
a:=1;
h:=E(m)^A[4][i][3];
for ex in [0..c2] do
if a = h then
break;
fi;
a:=a*g;
od;
if ex=c2 then
Print("\n The algebra is not a genuine cyclotomic algebra \n");
return fail;
fi;
Add(act,[A[4][i][1], acon[i] mod c2, ex]);
if pos < l then
coc2 := [];
for j in [pos+1..l] do
a:=1;
h:=E(m)^A[5][i][y[j]-i];
for ex in [0..c2] do
if a = h then
break;
fi;
a:=a*g;
od;
if ex=c2 then
Print("\n The algebra is not a genuine cyclotomic algebra \n");
return fail;
fi;
Add(coc2,ex);
od;
Add(coc1,coc2);
fi;
pos := pos+1;
od;
if l=1 then
return [A[1]*A[4][x][1],F,c2,act[1]];
else
return [A[1]*A[4][x][1],F,c2,act,coc1];
fi;
fi;
fi;
od;
## AT THIS POINT NO FACTORIZATION A=A1\otimes A2 WITH A1 AND SPLIT AND A2 CYCLOTOMIC HAS BEEN DISCOVERED
## NOW WE SEARCH FOR A FACTORIZATION WITH BOTH A1 AND A2 CYCLOTOMIC BUT NOT CYCLIC.
v := [1..k];
d1 := List(v,i->Filtered(v,j->i=j or e[i,j]<>0));
cls := [];
w:=v;
while w <> [] do
i:=w[1];
x:=[];
y:=[i];
while x<>y do
x:=y;
y:=Union(x,Concatenation(List(x,j->d1[j])));
w:=Difference(w,y);
od;
Add(cls,x);
od;
lc := Length(cls);
if lc = 1 then
return fail;
fi;
### WE CALCULATE ALL THE UNIONS OF CLASSES WITH AT LEAST TWO GENERATORS AND AT MOST HALF OF THE NUMBER OF GENERATORS
gcls := Filtered(SSortedList(Arrangements(cls),Union),x->Size(x)>1 and 2*Size(x) <= k);
SortBy(gcls,Size);
for x in gcls do
y := Difference(v,x);
F1:=NF(con,List(y,j->acon[j]));
c1 := CyclotomicExtensionGenerator(F1,F);
F2:=NF(con,List(x,j->acon[j]));
c2 := CyclotomicExtensionGenerator(F2,F);
if c1<>0 and c2<>0 then
# Construction of the first factor
g:=E(c1);
act := [];
l := Length(x);
pos := 1;
if l>1 then
coc1 := [];
fi;
for i in x do
h:=E(m)^A[4][i][3];
a := 1;
ex := 0;
for j in [0..c1-1] do
if a = h then
break;
else
ex:=ex+1;
a:=a*g;
fi;
od;
if ex=c1 then
Print("\n The algebra is not a genuine cyclotomic algebra \n");
return fail;
fi;
Add(act,[A[4][i][1],acon[i] mod c1,ex]);
if pos < l then
coc2 := [];
for j in [pos+1..l] do
a:=1;
h:=E(con)^A[5][i][x[j]-i];
for ex in [0..c1] do
if a = h then
break;
fi;
a:=a*g;
od;
if ex=c1 then
Print("\n The algebra is not a genuine cyclotomic algebra \n");
return fail;
fi;
Add(coc2,ex);
od;
Add(coc1,coc2);
fi;
pos := pos+1;
od;
if l=1 then
A1 := [A[1],F,c1,act[1]];
else
A1 := [A[1],F,c1,act,coc1];
fi;
# Construction of the second factor
g:=E(c2);
act := [];
l := Length(y);
pos := 1;
if l>1 then
coc1 := [];
fi;
for i in y do
h:=E(m)^A[4][i][3];
a := 1;
ex := 0;
for j in [0..c2-1] do
if a = h then
break;
else
ex:=ex+1;
a:=a*g;
fi;
od;
if ex=c2 then
Print("\n The algebra is not a genuine cyclotomic algebra \n");
return fail;
fi;
Add(act,[A[4][i][1], acon[i] mod c2, ex]);
if pos < l then
coc2 := [];
for j in [pos+1..l] do
a:=1;
h:=E(con)^A[5][i][y[j]-i];
for ex in [0..c2] do
if a = h then
break;
fi;
a:=a*g;
od;
if ex=c2 then
Print("\n The algebra is not a genuine cyclotomic algebra \n");
return fail;
fi;
Add(coc2,ex);
od;
Add(coc1,coc2);
fi;
pos := pos+1;
od;
if l=1 then
A2 := [A[1],F,c2,act[1]];
else
A2 := [A[1],F,c2,act,coc1];
fi;
# Print("\n", [A1,A2]);
s1 := SchurIndex(A1);
s2 := SchurIndex(A2);
if s1=1 then
if s2 =1 then
return [A[1]*Product(A1[4],x->x[1]),F];
else
A2[1] := A2[1]*Product(A1[4],x->x[1]);
return A2;
fi;
elif s2=1 then
A1[1] := A1[1]*Product(A2[4],x->x[1]);
return A1;
fi;
fi;
od;
return fail;
end);