function EigsToTracePowers(E,n)

Divs:=Prune(Divisors(n));
Traces:=[&+[j[2]*j[1]^i:j in E]:i in Divs];
// for i in Divs do Append(~Traces,&+{j[2]*j[1]^i:j in E});end for;
return Traces;
end function;



function DecreasingSequences(n,X)

Sort(~X);

if(#X eq 1) then return [[X[1]:i in [1..n]]]; end if;
if(n eq 1) then return [[i]:i in X]; end if;

Ans1:=DecreasingSequences(n,Prune(X));
Ans2:=DecreasingSequences(n-1,X);
for i in [1..#Ans2] do Ans2[i]:=Insert(Ans2[i],1,X[#X]); end for;
return Ans2 cat Ans1;
end function;

function ConjugationPowerMap(XX,g)
G:=Parent(g);
ord:=Order(g);
divs:=Prune(Divisors(ord));

PM:=[];
for i in divs do for j in [1..#XX] do
   if(IsConjugate(G,XX[j,3],g^i)) then Append(~PM,j); continue i; end if;
end for; end for;

return PM;

end function;


function BuildLargestModule(X,Irr)

A:=X;

repeat
  x:=0;
  for M in Irr do 
    E,rho:=Ext(M,A);
    if(Dimension(E) ge 1) then 
      repeat tau:=Random(E); until tau ne 0;
      n:=Dimension(A);
      A:=Extension(M,A,tau,rho);
      x:=1;
      if(Dimension(A) ne n+Dimension(M)) then "something wrong"; return X; end if;
    end if;
//    if(Dimension(E) gt 1) then 
  //    n:=Dimension(A);
    //  A:=MaximalExtension(M,A,E,rho);
      //x:=1;
  //    if(Dimension(A) ne n+Dimension(E)*Dimension(M)) then "something wrong"; return X; end if;
    //end if;
  end for;

until x eq 0;

return A;

end function;

function IsSelfDual(M)
Bool:=IsIsomorphic(M,Dual(M));
return Bool;
end function;

function IsIsomorphicToList(M,I)
  for i in I do
    if(IsIsomorphic(M,i)) then return true;
    end if;
  end for;
  return false;
end function;

function StripDuplicates(I)
  J:=[];
  for i in I do
    if(not(IsIsomorphicToList(i,J))) then Append(~J,i);
    end if;
  end for;
  return J;
end function;

function AppendWithoutDuplicates(X,Y)

Y:=StripDuplicates(Y);
Y2:=[]; for i in Y do if(not(IsIsomorphicToList(i,X))) then Append(~Y2,i); end if; end for;
return X cat Y2;

end function;

function IdentifyModule(M,I)
if(Dimension(M) eq 0) then return []; end if;
for i in [1..#I] do if(IsIsomorphic(I[i],M)) then return i; end if; end for;
return 0;
end function;

function IdentifyModules(J,I)
X:=[]; for i in J do Append(~X,IdentifyModule(i,I)); end for;
return Sort(X);
end function;

function IdentifyFactors(M,I)
if(Dimension(M) eq 0) then return []; end if;
return IdentifyModules(CompositionFactors(M),I);
end function;

function IdentifyLayers(M,I)
if(Dimension(M) eq 0) then return []; end if;
X:=[];
for i in SocleFactors(M) do
  Append(~X,IdentifyModules(CompositionFactors(i),I));
end for;
return Reverse(X);
end function;

function DescribeLayers(M,Irr,labs)
lays:=IdentifyLayers(M,Irr);
St:=[[labs[i]:i in j]:j in lays];
str:="";
for i in St do
  for j in i do
    str cat:=j; str cat:=",";
  end for;
  Prune(~str); str cat:="/";
end for;
return Prune(str);
end function;

function Swap(X,i,j)

temp:=X[i];
X[i]:=X[j];
X[j]:=temp;
return X;

end function;

function EigenvaluesOfElement(M,x)

X:=sub<Group(M)|x>;
return Eigenvalues(ActionGenerators(Restriction(M,X))[1]);
end function;

function IntersectionOfLists(Mods,Soc)
inter:=[];
for i in Mods do for j in Soc do if(i eq j) then Append(~inter,i); end if; end for; end for;
return Sort(inter);
end function;


function RemoveFromTop(M,Irr,ProjT,AllowedMods)
while(true) do
  ModsInRadical:=IdentifyFactors(M/JacobsonRadical(M),Irr);
  Removal:=IntersectionOfLists(AllowedMods,ModsInRadical);
  if(#Removal eq 0) then break; end if;
  Ims:=DirectSum([Irr[i]:i in Removal]);
  homo:=AHom(M,Ims);
  repeat x:=Random(homo); until Dimension(Image(x)) eq Dimension(Ims);
  M:=Kernel(x);
end while;
return M;
end function;


function RepresentPower(a,b)

if(b ge 10) then return IntegerToString(a) cat "^{" cat IntegerToString(b) cat "}";
elif(b gt 1) then return IntegerToString(a) cat "^" cat IntegerToString(b);
elif(b eq 1) then return IntegerToString(a); end if;
return "1";

end function;

function ActionOfUnipotent(Irr,g)

str:="$";
for i in Irr do SF:=SocleFactors(Restriction(i,sub<Group(i)|g>));
  Dims:=[Dimension(SF[#SF])]; 

  for j in [1..#SF-1] do Append(~Dims,Dimension(SF[#SF-j])-Dimension(SF[#SF-j+1])); end for;
  for j in [1..#Dims] do
    if(Dims[j] gt 0) then str cat:=RepresentPower(#Dims-j+1,Dims[j]) cat ","; end if;
  end for;

  Prune(~str); str cat:="$&$";
end for;

Prune(~str); Prune(~str);

return str;

end function;

function OrderByDimension(X)

Y:=Sort(SetToSequence(SequenceToSet([Dimension(i):i in X])));

X2:=[];

for i in Y do
  for j in X do
    if(Dimension(j) eq i) then Append(~X2,j); end if;
  end for;
end for;

return X2;

end function;

/* X be a set of modules, checked up to m. n is how many more we want to add.
*/

function GainSomeMoreModules(X,m,n)

a:=#X;

while(#X lt a+n) do
  m+:=1;
  X:=AppendWithoutDuplicates(X,CompositionFactors(TensorProduct(X[1],X[m])));
#X;
end while;

return X,m;

end function;

function ExpressElementInGenerators(G,x)
d:=#Generators(G);
ords:=[Order(G.i):i in [1..d]];
AbIm:=AbelianGroup(ords);
phi:=Isomorphism(G,AbIm,[G.i:i in [1..d]],[AbIm.i:i in [1..d]]);
return ElementToSequence(x@phi);
end function;

/* This function takes a sequence X of sequences and produces the Cartesian product of these sequences,
   namely all sequences whose ith term comes from the ith term of X. */

function AllSequences(X)

if(#X eq 1) then return [[i]:i in X[1]]; end if;
A:=AllSequences(Prune(X));
return [Append(i,j):i in A,j in X[#X]];
end function;

/* This function, for a homocyclic group of exponent n, takes an element El and constructs all elements whose
   mth power is El. */

function ConstructPreimages(El,n,m)
Powers:=[];
for i in El do Append(~Powers,[j:j in [0..n-1] | (m*j mod n) eq i]); end for;
return AllSequences(Powers);
end function;

function ProduceGroupElements(G,Seqs)

return [&*[G.i^j[i]:i in [1..#Generators(G)]]:j in Seqs];
end function;

function ProduceGroupElement(G,Seq)

return &*[G.i^Seq[i]:i in [1..#Generators(G)]];
end function;
