Quellcodebibliothek Statistik Leitseite products/sources/formale Sprachen/GAP/pkg/wedderga/lib/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 7.6.2025 mit Größe 51 kB image not shown  

Quelle  div-alg.gi   Sprache: unbekannt

 
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);

[ Dauer der Verarbeitung: 0.52 Sekunden  ]