Impressum specht.gi
Interaktion und Portierbarkeitunbekannt
|
|
Haftungsausschluß.gi KontaktUnknown {[0] [0] [0]}diese Dinge liegen außhalb unserer Verantwortung #######################################################################
## Hecke - specht.gi : the kernel of Hecke ##
## ##
## A GAP package for calculating the decomposition numbers of ##
## Hecke algebras of type A (over fields of characteristic ##
## zero). The functions provided are primarily combinatorial in ##
## nature. Many of the combinatorial tools from the (modular) ##
## representation theory of the symmetric groups appear in the ##
## package. ##
## ##
## These programs, and the enclosed libraries, are distributed ##
## under the usual licensing agreements and conditions of GAP. ##
## ##
## Dmitriy Traytel ##
## (heavily using the GAP3-package SPECHT 2.4 by Andrew Mathas) ##
## ##
#######################################################################
## Hecke 1.0: June 2010:
## - Translated to GAP4
## SPECHT Change log
## 2.4:
## - fixed more bugs in H.valuation; returned incorrect answers before
## when e=0 or e=p (symmetric group case).
## - fixed bug in Dq(), via Sasha Kleshchev.
## 2.3:
## - fixed bug in H.valuation reported by Johannes Lipp
## - fixed bug in Sq() reported by Johannes Lipp.
## - corrected FindDecompositionMatrix() so that it updates the matrices
## CrystalMatrices[] and DecompositionMatrices[] after calculating a
## crystalized decomposition matrix.
## 2.2: June 1996: various changes requested by the referee.
## - mainly changing function names.
## - DecompositionMatrix changed so that it no longer attempts to
## calculate decomposition matrices in the finite field case; added
## CalculateDecompositionMatrix() to do this.
## - replaced Matrix() function with MatrixDecompositionMatrix() and
## added the function DecompositionMatrixMatix().
## 2.1: April 1996:
## - Added a filename argument to SaveDecompositionMatrix and made it
## save the non-decomposition matrices under (more) sensible names; the
## later is done using the existence of a record component d.matname.
## Need to do something here about reading such matrices in (this can be
## done using DecompositionMatrix)..
## - Changed ReadDecompositionMatrix so that it automatically reads the
## format of version 1.0 files (and deleted ReadOldDecompositionMatrix).
## Also fixed a bug here which was causing confusion between Hecke algebra
## and Schur algebra matrices.
## - Renamed FindDecompositionMatrix as KnownDecompositionMatrix because it
## doesn't try to calculate a crytalized decomposition matrix; the new
## FindDecompositionMatrix will return the decomposition matrix if at all
## possible. In particular, this fixes a 'bug' in SimpleDimension.
## - Rewrote AdjustmentMatrix so that it actually works.
## - Changed P()->S() module conversions so that it no longer requires
## the projective module to have positive coefficients (and fixed bug in
## matrix ops).
## 2.0: March 1996:
## - LLT algorithm implemented for calculating crystal basis of
## the Fock space and hence by specialization the decomposition
## matrices for all Hecke algebras over fields of characteristic
## zero; most of the work is done by the internal function Pq().
## This required a new set of 'module' types ("Pq", "Sq", and "Dq"),
## with corresponding operation sets H.operations.X. In particular,
## these include q-induction and q-restriction, effectively allowing
## computations with $U_q(\hat sl_e)$ on the Fock space.
## - crystallized decomposition matrices added and decomposition
## matrix type overhauled. d.d[c] is now a list of records with
## partitions replaced by references to d.rows etc. Changed format
## of decomposition matrix library files so as to handle polynomial
## entries in the matrices..
## - printing of Specht records changed allowing more compact and
## readable notation. eg. S(1,1,1,1)->S(1^4). (see SpechtPrintFn).
## - reversed order of parts and coeffs records in H.S(), d.d etc;
## these lists are now sets which improves use of Position().
## - reorganised the Specht function and the record H() which it returns;
## in particular added H.info.
## - extended SInducedModule() and SRestrict to allow multiple inducing and
## restricting (all residues).
## 1.0: December 1995: initial release.
######################################################################
## Here is a description of the structure of the main records used
## in SPECHT
#### In GAP4 all "operations"-fields do not exist. They are replaced
#### by top-level operations with some filter restrictions
## 1. Specht()
## Specht() is the main function in specht.g, it returns a record 'H'
## which represents the family of Hecke algebras, or Schur algebras,
## corresponding to some fixed field <R> and parameter <q>. 'H' has
## the components:
## IsSpecht : is either 'true' or 'false' depending on whether
## 'H' is a Hecke algebra or Schur algebra resp.
#### This function is obsolete in the GAP4 version - it is replaced
#### by the filter IsHecke
## S(), P(), D() : these three functions return records which
## represent Specht modules, PIMs, and simple
## 'H' modules respectively. These functions exist
## only when 'H' is a Hecke algebra record.
#### Use MakeSpecht(H,...) instead of H.S(...)
## W(), P(), F() : these are the corresponding functions for Weyl
## modules, PIMs, and simple modules of Schur algbras.
#### Use MakeSpecht(S,...) instead of S.W(...)
## info : this is a record with components
## version: SPECHT version number,
## Library: path to SPECHT library files
## SpechtDirectory: addition directory searched by
## SPECHT (defaults to current directory)
## Indeterminate: the indeterminate used by SPECHT
## in the LLT algorithm when H.p=0.
## operations : apart from the obvious things like the Print()
## function for 'H' this record also contains the
## operation records for the modules S(), P() etc.
## as well as functions for manipulating these records
## and accessing decomposition matrix files. The most
## most important of these are:
## S, P, D, Pq, Sq, Dq : operations records for modules
#### Most functions are now on toplevel
## New : creation function for modules. Internally
## modules are created via
## H.operations.new(module,coeffs,parts)
## where module is one of "S", "P", "D", "Sq", "Pq",
## or "Dq" ("S" and "D" are used even for Schur
## algebras), coeffs is an integer or a *set* of
## integers and parts is a partition or a *set* of
## partitions. In any programs the use of New is
## better than H.S(mu), for example, because the
## function names are different for Hecke and Schur
## algebras. Note that coeffs and parts must be
## ordered reverse lexicographically (ie. they are
## *sets*).
#### Use Module(H,...) instead of H.operations.New(...)
## Collect: like New() except that coeffs and parts
## need not be sets (and may contain repeats).
#### Use Collect(H,...) instead of H.operations.Collect(...)
## NewDecompositionMatrix : creates a decomposition
## matrix.
#### Use ReadDecompositionMatrix(H,...) instead of H.operations.ReadDecompositionMatrix(...)
## ReadDecompositionMatrix : reads, and returns, a
## decomposition matrix file.
#### Use KnownDecompositionMatrix(H,...) instead of H.operations.KnownDecompositionMatrix(...)
## KnownDecompositionMatrix : returns a decomposition
## matrix of a given size; will either extract this
## matrix from Specht's internal lists or call
## ReadDecompositionMatrix(), or try to calculate
## the decomposition matrix (without using the
## crystalized decomposition matrices).
#### Use FindDecompositionMatrix(H,...) instead of H.operations.FindDecompositionMatrix(...)
## FindDecompositionMatrix : like KnownDM except that
## it will calculate the crystalized DM if needed.
## Ordering : a function for ordering partitions; controls how
## decomposition matrices for H are printed.
#### Use SetOrdering(...) to control the output
## e : order of <q> in <R>
#### Use OrderOfQ(...) to extract the e from an algebra or a module
#### corresponding to an algebra
## p : characteristic of <R>
## valuation : the valuation map of [JM2]; used primarily by
## the q-Schaper theorem.D
## HeckeRing : bookkeeping string used primarily in searching for
## library files.
## Pq(), Sq() : Functions for computing elements of the Fock space
## when H.p=0 (used in LLT algorithm). Note that there is
## no Dq; also unlike their counter parts S(), P(), and
## D() they accept only partitions as arguments.
#### Use MakeFockPIM(H,...) instead of H.Pq(...)
#### Use MakeFockSpecht(H,...) instead of H.Sq(...)
##
## 2. The module functions S(), P() and D() (and Schur equivalents)
## These functions return record 'x' which represents some 'H'--module.
## 'x' is a record with the following components:
## H : a pointer back to the corresponding algebra
## module : one of "S", "P", "D", "Sq", "Pq", or "Dq", (not "W", or "F").
## coeffs : a *set* of coefficients
## parts : the corresponding *set* of partitions
## operations :
## + - * / : for algebraic manipulations
## Print : calls PrintModule
## Coefficient : returns the coefficient of a given partition
#### Use Coefficient(x,...) instead of x.operations.Coefficient(...)
## PositiveCoefficients : true if all coefficients are non-negative
## IntegralCoefficients : true if all coefficients are integral
## InnerProduct : computes the 'Kronecker' inner product
## Induce, Restrict, SInduce, SRestrict : induction and restriction
## functions taylored to 'x'. These functions convert 'x'
## to a linear combination of Specht modules, induce and
## then convert back to the type of 'x' (if possible).
## Quantized versions are applied as appropriate.
## S, P, D : functions for rewriting 'x' into the specified type
## (so, for example, S('x') rewrites 'x' as a linear
## combination of Specht modules).
## 'x'.operations is a pointer to 'H'.operations.('x'.module).
##
## 3. DecompositionMatrices
## Decomposition matrices 'd' in Specht are represented as records with the
## following components:
##
## d : a list, indexed by d.cols, where each entry is a record
## corresponding to a column of 'd'; this record has components
## two * sets* coeffs and parts, where parts is the index of the
## corresponding partition in d.rows.
## rows : the *set* of the partitions which make up the rows or 'd'.
## cols : the *set* of the partitions which make up the rows or 'd'.
## inverse : a list of records containing the inverse of 'd'. These
## records are computed only as needed.
## dimensions : a list of the dimensions of the simple modules; again
## computed only as needed.
## IsDecompositionMatrix : false if 'd' is a crystallized decomposition
## matrix, and true otherwise.
## H :a pointer back to the corresponding algebra
## operations :
## = : equality.
## Print, TeX, Matrix : printing, TeX, and a GAP Matrix.
## AddIndecomposable : for adding a PIM to 'd'.
## Store : for updating Specht's internal record of 'd'.
## S, P, D: for accessing the entries of 'd' and using 'd' to
## convert between the various types of 'H'--modules.
## These are actually records, each containing three
## functions S(), P(), and D(); so X.Y() tells 'd' how
## to write an X-module as a linear combination of Y-modules.
## Invert : calculates D(mu) using 'd'.
## IsNewIndecomposable : the heart of the 'IsNewIndecomposable'
## function.
## Induce : for inducing decomposition matrices (non--crystallized).
## P : a short-hand for d.H.P('d',<mu>).
###########################################################################
## Specht() is the main function in the package, although in truth it is
## little more than a wrapper for the functions S(), P(), and D().
## Originally, I had these as external functions, but decided that it
## was better to tie these functions to e=H.e as strongly as possible.
InstallMethod(Specht_GenAlgebra,"generate a type-Algebra object",
[IsString,IsInt,IsInt,IsFunction,IsString],
function(type,e,p,valuation,HeckeRing)
local H;
if not IsPrime(p) and p<>0
then Error("Specht(<e>,<p>,<val>), <p> must be a prime number");
fi;
H := rec(
e:=e,
p:=p,
valuation:=valuation,
HeckeRing:=HeckeRing,
## bits and pieces about H
info:=rec(version:=PackageInfo("hecke")[1].Version,
Library:=Directory(
Concatenation(DirectoriesPackageLibrary("hecke")[1]![1],"e",
String(e),"/")),
## We keep a copy of SpechtDirectory in H so that we have a
## chance of finding new decomposition matrices when it changes.
SpechtDirectory:=Directory(".")),
## This record will hold any decomposition matrices which Specht()
## (or rather its derivatives) read in. This used to be a public
## record; it is now private because q-Schur algebra matrices and
## Hecke algebra matrices might need to coexist.
DecompositionMatrices:=[],
## for ordering the rows of the decomposition matrices
## (as it is common to all decomposition matrices it lives here)
Ordering:=Lexicographic,
);
if p = 0
then
## This list will hold the crystallized decomposition matrices (p=0)
H.CrystalMatrices:=[];
H.Indeterminate:=Indeterminate(Integers);
SetName(H.Indeterminate,"v");
else H.Indeterminate:=1;
fi;
if type = "Schur" then
Objectify(SchurType,H);
else
Objectify(HeckeType,H);
fi;
return H;
end
);
InstallMethod(Specht_GenAlgebra,"generate a type-Algebra object",
[IsString,IsInt,IsInt,IsFunction],
function(type,e,p,val) local ring;
if not IsPrime(p)
then Error("Specht(<e>,<p>,<val>), <p> must be a prime number");
fi;
if e=p then
ring:=Concatenation("p",String(p),"sym");
return Specht_GenAlgebra(type,e,p,val,ring);
else
return Specht_GenAlgebra(type,e,p,val,"unknown");
fi;
end
);
InstallMethod(Specht_GenAlgebra,"generate a type-Algebra object",
[IsString,IsInt,IsInt],
function(type,e,p) local val, ring;
if not IsPrime(p)
then Error("Specht(<e>,<p>,<val>), <p> must be a prime number");
fi;
if e=p then
ring:=Concatenation("p",String(p),"sym");
## return the exponent of the maximum power of p dividing x
val:=function(x) local i;
i:=0;
while x mod p=0 do
i:=i+1;
x:=x/p;
od;
return i;
end;
else
ring:=Concatenation("e",String(e), "p",String(p));
## return the exponent of the maximum power of p that
## divides e^x-1.
val:=function(x) local i;
if x mod e=0 then return 0;
else
i:=0;
while x mod p=0 do
i:=i+1;
x:=x/p;
od;
return p^i;
fi;
end;
fi;
return Specht_GenAlgebra(type,e,p,val,ring);
end
);
InstallMethod(Specht_GenAlgebra,"generate a type-Algebra object",
[IsString,IsInt],
function(type,e) local val;
if e=0 then val:=x->x;
else
val:=function(x)
if x mod e = 0 then return 1;
else return 0;
fi;
end;
fi;
return Specht_GenAlgebra(type,e,0,val,Concatenation("e",String(e), "p0"));
end
);
InstallMethod(Specht,"generate a Hecke-Algebra object",[IsInt],
function(e) return Specht_GenAlgebra("Specht",e); end
);
InstallMethod(Specht,"generate a Hecke-Algebra object",[IsInt,IsInt],
function(e,p) return Specht_GenAlgebra("Specht",e,p); end
);
InstallMethod(Specht,"generate a Hecke-Algebra object",[IsInt,IsInt,IsFunction],
function(e,p,val) return Specht_GenAlgebra("Specht",e,p,val); end
);
InstallMethod(Specht,"generate a Hecke-Algebra object",[IsInt,IsInt,IsFunction,IsString],
function(e,p,val,ring) return Specht_GenAlgebra("Specht",e,p,val,ring); end
);
InstallMethod(Schur,"generate a Schur-Algebra object",[IsInt],
function(e) return Specht_GenAlgebra("Schur",e); end
);
InstallMethod(Schur,"generate a Schur-Algebra object",[IsInt,IsInt],
function(e,p) return Specht_GenAlgebra("Schur",e,p); end
);
InstallMethod(Schur,"generate a Schur-Algebra object",[IsInt,IsInt,IsFunction],
function(e,p,val) return Specht_GenAlgebra("Schur",e,p,val); end
);
InstallMethod(Schur,"generate a Schur-Algebra object",[IsInt,IsInt,IsFunction,IsString],
function(e,p,val,ring) return Specht_GenAlgebra("Schur",e,p,val,ring); end
);
InstallImmediateMethod(Characteristic, IsAlgebraObj, 0,
function(H) return H!.p; end
);
InstallImmediateMethod(IsZeroCharacteristic, IsAlgebraObj, 0,
function(H) return H!.p = 0; end
);
InstallImmediateMethod(OrderOfQ, IsAlgebraObj, 0,
function(H) return H!.e; end
);
InstallImmediateMethod(OrderOfQ, IsAlgebraObjModule, 0,
function(x) return x!.H!.e; end
);
InstallMethod(SetOrdering,"writing access to H.Ordering",
[IsAlgebraObj,IsFunction],
function(H,ord) H!.Ordering := ord; end
);
InstallMethod(SpechtCoefficients,"reading access to S.coeffs",[IsHeckeSpecht],
function(S) return S!.coeffs; end
);
InstallMethod(SpechtPartitions,"reading access to S.parts",[IsHeckeSpecht],
function(S) return S!.parts; end
);
## FORMER TOPLEVEL FUNCTIONS ###################################################
#F Calculates the dimensions of the simple modules in d
## Usage: SimpleDimension(d) -> prints all simple dimensions
## SimpleDimension(H,n) -> prints all again
## SimpleDimension(H,mu) or SimpleDimension(d,mu) -> dim D(mu)
InstallMethod(SimpleDimensionOp,
"all simple dimensions from decomposition matrix",[IsDecompositionMatrix],
function(d) local cols, collabel, M, c, x;
if IsSchur(d!.H) then
Print("# SimpleDimension() not implemented for Schur algebras\n");
return fail;
fi;
cols:=StructuralCopy(d!.cols);
if d!.H!.Ordering=Lexicographic then
cols:=cols{[Length(cols),Length(cols)-1..1]};
else Sort(cols, d!.H!.Ordering);
fi;
cols:=List(cols, c->Position(d!.cols,c));
collabel:=List([1..Length(cols)], c->LabelPartition(d!.cols[cols[c]]));
M:=Maximum(List(collabel, Length))+1;
for c in [1..Length(cols)] do
Print(String(collabel[c],-M),": ");
if IsBound(d!.dimensions[cols[c]]) then
Print(d!.dimensions[cols[c]],"\n");
else
x:=MakeSimpleOp(d,d!.cols[cols[c]]);
if x=fail then Print("not known\n");
else
d!.dimensions[cols[c]]:=Sum([1..Length(x!.parts)],
r->x!.coeffs[r]*SpechtDimension(x!.parts[r]));
Print(d!.dimensions[cols[c]],"\n");
fi;
fi;
od;
return true;
end
);
InstallMethod(SimpleDimensionOp,
"simple dimensions of a partition from decomposition matrix",
[IsDecompositionMatrix,IsList],
function(d,mu) local c, x;
c:=Position(d!.cols,mu);
if c=fail then
Print("# SimpleDimension(<d>,<mu>), <mu> is not in <d>.cols\n");
return fail;
else
if not IsBound(d!.dimensions[c]) then
x:=MakeSimpleOp(d,d!.cols[c]);
if x=fail then return fail;
else d!.dimensions[c]:=Sum([1..Length(x!.parts)],
r->x!.coeffs[r]*SpechtDimension(x!.parts[r]));
fi;
fi;
return d!.dimensions[c];
fi;
end
);
InstallMethod(SimpleDimensionOp,
"all simple dimensions from algebra",[IsAlgebraObj,IsInt],
function(H,n) local d;
d:=FindDecompositionMatrix(H,n);
if d=fail then
Print("# SimpleDimension(H,n), the decomposition matrix of H_n is ",
"not known.\n");
return fail;
fi;
return SimpleDimensionOp(d);
end
);
InstallMethod(SimpleDimensionOp,
"simple dimensions of a partition from algebra",[IsAlgebraObj,IsList],
function(H,mu) local d;
d:=FindDecompositionMatrix(H,Sum(mu));
if d=fail then
Print("# SimpleDimension(H,mu), the decomposition matrix of H_Sum(mu) is",
" not known.\n");
return fail;
fi;
return SimpleDimensionOp(d,mu);
end
); # SimpleDimension
#P returns a list of the e-regular partitions occurring in x
InstallMethod(ListERegulars,"e-regular partitions of a module",
[IsAlgebraObjModule],
function(x) local e,parts,coeffs,p;
e:=x!.H!.e;
parts:=x!.parts;
coeffs:=x!.coeffs;
if e=0 then return parts;
elif x=0*x then return [];
else return List(Filtered([Length(parts),Length(parts)-1..1],
p->IsERegular(e,parts[p])),p->[coeffs[p], parts[p]]);
fi;
end
); # ListERegulars
##P Print the e-regular partitions in x if IsSpecht(x); on the other hand,
### if IsDecompositionMatrix(x) then return the e-regular part of the
### decomposition matrix.
InstallMethod(ERegulars,"e-regular part of the given decomposition matrix",
[IsDecompositionMatrix],
function(d) local regs, y, r, len;
regs:=DecompositionMatrix(d!.H,d!.rows,d!.cols,not IsCrystalDecompositionMatrix(d));
regs!.d:=[]; #P returns a list of the e-regular partitions occurring in x
for y in [1..Length(d!.cols)] do
if IsBound(d!.d[y]) then
regs!.d[y]:=rec(parts:=[], coeffs:=[]);
for r in [1..Length(d!.d[y].parts)] do
len:=Position(d!.cols,d!.rows[d!.d[y].parts[r]]);
if len<>fail then
Add(regs!.d[y].parts,len);
Add(regs!.d[y].coeffs,d!.d[y].coeffs[r]);
fi;
od;
fi;
od;
regs!.rows:=regs!.cols;
return regs;
end
);
InstallMethod(ERegulars, "print e-regular partitions of a module",
[IsAlgebraObjModule],
function(x) local len, regs, y;
len:=0;
regs:=ListERegulars(x);
if regs=[] or IsInt(regs[1]) then Print(regs, "\n");
else
for y in regs do
if (len + 5 + 4*Length(y[2])) > 75 then len:=0; Print("\n"); fi;
if y[1]<>1 then Print(y[1], "*"); len:=len + 3; fi;
Print(y[2], " ");
len:=len + 5 + 4*Length(y[2]);
od;
Print("\n");
fi;
end
); # ERegulars
#F Returns true if S(mu)=D(mu) - note that this implies that mu is e-regular
## (if mu is not e-regular, fail is returned). -- see [JM2]
## IsSimple(H,mu)
## ** uses H.valuation
InstallMethod(IsSimpleModuleOp,
"test whether the given partition defines a simple module",
[IsAlgebraObj,IsList],
function(H,mu) local mud, simple, r, c, v;
if not IsERegular(H!.e,mu) then return false;
elif mu=[] then return true; fi;
mud:=ConjugatePartition(mu);
simple:=true; c:=1;
while simple and c <=mu[1] do
v:=H!.valuation(mu[1]+mud[c]-c);
simple:=ForAll([2..mud[c]], r->v=H!.valuation(mu[r]+mud[c]-c-r+1));
c:=c+1;
od;
return simple;
end
); #IsSimpleModule
#F Split an element up into components which have the same core.
## Usage: SplitECores(x) - returns as list of all block components
## SplitECores(x,lambda) - returns a list with (i) core lambda,
## (ii) the same core as lambda, or (iii) the same core as the first
## element in lambda if IsSpecht(lambda).
InstallMethod(SplitECoresOp,"for a single module",[IsAlgebraObjModule],
function(x) local cores, c, cpos, y, cmp;
if x=fail or x=0*x then return []; fi;
cores:=[]; cmp:=[];
for y in [1..Length(x!.parts)] do
c:=ECore(x!.H!.e, x!.parts[y]);
cpos:=Position(cores, c);
if cpos=fail then
Add(cores, c);
cpos:=Length(cores);
cmp[cpos]:=[[],[]];
fi;
Add(cmp[cpos][1], x!.coeffs[y]);
Add(cmp[cpos][2], x!.parts[y]);
od;
for y in [1..Length(cmp)] do
cmp[y]:=Module(x!.H,x!.module,cmp[y][1],cmp[y][2]);
od;
return cmp;
end
);
InstallMethod(SplitECoresOp,"for a module and a partition",
[IsAlgebraObjModule,IsList],
function(x,mu) local c, cpos, y, cmp;
c:=ECore(x!.H!.e, mu);
cmp:=[ [],[] ];
for y in [1..Length(x!.parts)] do
if ECore(x!.H!.e, x!.parts[y])=c then
Add(cmp[1], x!.coeffs[y]);
Add(cmp[2], x!.parts[y]);
fi;
od;
cmp:=Module(x!.H,x!.module, cmp[1], cmp[2]);
return cmp;
end
);
InstallMethod(SplitECoresOp,"for a module and a specht module",
[IsAlgebraObjModule,IsAlgebraObjModule],
function(x,s) local c, cpos, y, cmp;
c:=ECore(s!.H!.e, s!.parts[Length(x!.parts)]);
cmp:=[ [],[] ];
for y in [1..Length(x!.parts)] do
if ECore(x!.H!.e, x!.parts[y])=c then
Add(cmp[1], x!.coeffs[y]);
Add(cmp[2], x!.parts[y]);
fi;
od;
cmp:=Module(x!.H,x!.module, cmp[1], cmp[2]);
return cmp;
end
); #SplitECores
#F This function returns the image of <mu> under the Mullineux map using
## the Kleshcehev(-James) algorithm, or the supplied decomposition matrix.
## Alternatively, given a "module" x it works out the image of x under
## Mullineux.
## Usage: MullineuxMap(e|H|d, mu) or MullineuxMap(x)
InstallMethod(MullineuxMapOp,"image of x under Mullineux",[IsAlgebraObjModule],
function(x) local e, v;
e := x!.H!.e;
if x=fail or not IsERegular(e,x!.parts[Length(x!.parts)]) then
Print("# The Mullineux map is defined only for e-regular partitions\n");
return fail;
fi;
if x=fail or x=0*x then return fail; fi;
if IsHeckeSpecht(x) then
if Length(x!.module)=1 then
return Collect(x!.H,x!.module,x!.coeffs,
List(x!.parts, ConjugatePartition));
else
v:=x!.H!.info.Indeterminate;
return Collect(x!.H,x!.module,
List([1..Length(x!.coeffs)],
mu->Value(v^-EWeight(e,x!.parts[mu])*x!.coeffs[mu],v^-1)),
List(x!.parts,ConjugatePartition) );
fi;
elif Length(x!.module)=1 then
return Sum([1..Length(x!.coeffs)],
mu->Module(x!.H,x!.module,x!.coeffs[mu],
MullineuxMap(e,x!.parts[mu])));
else
v:=x!.H!.info.Indeterminate;
return Sum([1..Length(x!.coeffs)],
mu->Module(x!.H,x!.module,
Value(v^-EWeight(e,x!.parts[mu])*x!.coeffs[mu]),
MullineuxMap(e,x!.parts[mu])));
fi;
end
);
InstallMethod(MullineuxMapOp,"for ints: image of <mu> under the Mullineux map",
[IsInt,IsList],
function(e,mu)
if not IsERegular(e,mu) then ## q-Schur algebra
Error("# The Mullineux map is defined only for e-regular ",
"partitions\n");
fi;
return PartitionGoodNodeSequence(e,
List(GoodNodeSequence(e,mu),x->-x mod e));
end
);
InstallMethod(MullineuxMapOp,
"for algebras: image of <mu> under the Mullineux map",
[IsAlgebraObj,IsList],
function(H,mu)
return MullineuxMapOp(H!.e,mu);
end
);
InstallMethod(MullineuxMapOp,
"for decomposition matrices: image of <mu> under the Mullineux map",
[IsDecompositionMatrix,IsList],
function(d,mu) local e, x;
e := d!.H!.e;
if not IsERegular(e,mu) then ## q-Schur algebra
Error("# The Mullineux map is defined only for e-regular ",
"partitions\n");
fi;
x:=d!.H!.P(d,mu);
if x=fail or x=0*x then
Print("MullineuxMap(<d>,<mu>), P(<d>,<mu>) not known\n");
return fail;
else return ConjugatePartition(x!.parts[1]);
fi;
return true;
end
); # MullineuxMap
#F Calculates the Specht modules in sum_{i>0}S^lambda(i) using the
## q-analogue of Schaper's theorem.
## Uses H.valuation.
## Usage: Schaper(H,mu);
InstallMethod(SchaperOp,"calculates Specht modules",[IsAlgebraObj,IsList],
function(H,mu)
local mud, schaper, hooklen, c, row, r, s, v;
Sort(mu); mu:=mu{[Length(mu),Length(mu)-1..1]};
mud:=ConjugatePartition(mu);
hooklen:=[];
for r in [1..Length(mu)] do
hooklen[r]:=[];
for c in [1..mu[r]] do
hooklen[r][c]:=mu[r] + mud[c] - r - c + 1;
od;
od;
schaper:=Module(H,"S",0,[]);
for c in [1..mu[1]] do
for row in [1..mud[1]] do
for r in [row+1..mud[1]] do
if mu[row] >=c and mu[r] >=c then
v:=H!.valuation(hooklen[row][c])
- H!.valuation(hooklen[r][c]);
if v<>0 then
s:=AddRimHook(RemoveRimHook(mu,r,c,mud),row,hooklen[r][c]);
if s<>fail then
schaper:=schaper+Module(H,"S",
(-1)^(s[2]+mud[c]-r)*v,s[1]);
fi;
fi;
fi;
od;
od;
od;
return schaper;
end
); #Schaper
#F returns the matrix of upper bounds on the entries in the decomposition
## matrix <d> given by the q-Schaper theorem
## *** undocumented
InstallMethod(SchaperMatrix,"upper bounds of entries of a decomposition matrix",
[IsDecompositionMatrix],
function(d) local r, C, c, coeff, sh, shmat;
shmat:=DecompositionMatrix(d!.H,d!.rows,d!.cols,true);
shmat!.d:=List(shmat!.cols, c->rec(parts:=[],coeffs:=[]));
C:=Length(d!.cols)+1; ## this keeps track of which column we're up to
for r in [Length(d!.rows),Length(d!.rows)-1..1] do
if d!.rows[r] in d!.cols then C:=C-1; fi;
sh:=Schaper(d!.H,d!.rows[r]);
for c in [C..Length(d!.cols)] do
coeff:=InnerProduct(sh,MakePIMSpechtOp(d,d!.cols[c]));
if coeff<>fail and coeff<>0*coeff then
Add(shmat!.d[c].parts,r);
Add(shmat!.d[c].coeffs,coeff);
fi;
od;
od;
sh:=[];
for c in [1..Length(d!.d)] do
Add(shmat!.d[c].parts, Position(shmat!.rows,shmat!.cols[c]));
Add(shmat!.d[c].coeffs,1);
od;
shmat!.matname:="Schaper matrix";
return shmat;
end
);
## FORMER DECOMPOSITION MATRICES TOPLEVEL FUNCTIONS ############################
##############################################################
## Next some functions for accessing decomposition matrices ##
##############################################################
#F Returns the decomposition number d_{mu,nu}; row and column removal
## are used if the projective P(nu) is not already known.
## Usage: DecompositionNumber(H,mu,nu), or
## DecompositionNumber(d,mu,nu);
## If unable to calculate the decomposition number we return false.
## Note that H.IsSpecht is false if we are looking at decomposition matrices
## of a q-Schur algebra and true for a Hecke algebra.
InstallMethod(DecompositionNumber,
"for a decomposition matrix and two partitions",
[IsDecompositionMatrix,IsList,IsList],
function(d,mu,nu) local Pnu;
if mu=nu then return 1;
elif not Dominates(nu,mu) then return 0;
else
Pnu:=MakePIMSpechtOp(d,nu);
if Pnu<>fail then return Coefficient(Pnu,mu); fi;
return Specht_DecompositionNumber(d!.H,mu,nu);
fi;
end
);
InstallMethod(DecompositionNumber,"for an algebra and two partitions",
[IsAlgebraObj,IsList,IsList],
function(H,mu,nu) local Pnu;
Pnu:=MakeSpechtOp(Module(H,"P",1,nu),true);
if Pnu<>fail then return Coefficient(Pnu,mu); fi;
if not IsSchur(H) and not IsERegular(H!.e, nu) then
Error("DecompositionNumber(H,mu,nu), <nu> is not ",H!.e,"-regular");
fi;
return Specht_DecompositionNumber(H,mu,nu);
end
);
InstallMethod(Specht_DecompositionNumber,
"internal: for an algebra and two partitions",
[IsAlgebraObj,IsList,IsList],
function(H,mu,nu) local Pnu, RowAndColumnRemoval;
## Next we try row and column removal (James, Theorem 6.18)
## (here fn is either the identity or conjugation).
RowAndColumnRemoval:=function(fn) local m,n,i,d1,d2;
## x, mu, and nu as above
mu:=fn(mu); nu:=fn(nu);
m:=0; n:=0; i:=1;
while i<Length(nu) and i<Length(mu) do
m:=m+mu[i]; n:=n+nu[i];
if m=n then
d2:=DecompositionNumber(H, fn(mu{[i+1..Length(mu)]}),
fn(nu{[i+1..Length(nu)]}));
if d2=0 then return d2;
elif IsInt(d2) then
d1:=DecompositionNumber(H, fn(mu{[1..i]}),fn(nu{[1..i]}));
if IsInt(d1) then return d1*d2; fi;
fi;
fi;
i:=i+1;
od;
return fail;
end;
Pnu:=RowAndColumnRemoval(a->a);
if Pnu=fail then Pnu:=RowAndColumnRemoval(ConjugatePartition); fi;
return Pnu;
end
);
#F Returns a list of those e-regular partitions mu such that Px-P(mu)
## has positive coefficients (ie. those partitions mu such that P(mu)
## could potentially split off Px). Simple minded, but useful.
InstallMethod(Obstructions,"for a decomposition matrix and a module",
[IsDecompositionMatrix,IsAlgebraObjModule],
function(d,Px) local obs, mu, Pmu, possibles;
obs:=[];
if not IsSchur(d!.H) then
possibles:=Filtered(Px!.parts, mu->IsERegular(Px!.H!.e, mu));
else possibles:=Px!.parts;
fi;
for mu in possibles do
if mu<>Px!.parts[Length(Px!.parts)] then
Pmu:=MakePIMSpechtOp(d,mu);
if Pmu=fail or PositiveCoefficients(Px-Pmu) then Add(obs,mu); fi;
fi;
od;
return obs{[Length(obs),Length(obs)-1..1]};
end
);
## Interface to d.operations.IsNewDecompositionMatrix. Returns true
## if <Px> contains an indecomposable not listed in <d> and false
## otherwise. Note that the value of <Px> may well be changed by
## this function. If the argument <mu> is used then we assume
## that all of the decomposition numbers down given by <Px> down to
## <mu> are correct. Note also that if d is the decomposition matrix
## for H(Sym_{r+1}) then the decomposition matrix for H(Sym_r) is passed
## to IsNewDecompositionMatrix.
## Usage: IsNewIndecomposable(<d>,<Px> [,<mu>]);
## If <mu> is not supplied then we set mu:=true; this
## turns on the message printing in IsNewIndecomposable().
InstallMethod(IsNewIndecomposableOp,
"for a decomposition matrix and a module",
[IsDecompositionMatrix,IsAlgebraObjModule],
function(d,Px) local oldd;
oldd:=FindDecompositionMatrix(d!.H,Sum(d!.rows[1])-1);
return IsNewIndecomposableOp(d!.H,d,Px,oldd,[]);
end
);
InstallMethod(IsNewIndecomposableOp,
"for a decomposition matrix, a module and a partition",
[IsDecompositionMatrix,IsAlgebraObjModule,IsList],
function(d,Px,mu) local oldd;
oldd:=FindDecompositionMatrix(d!.H,Sum(d!.rows[1])-1);
return IsNewIndecomposableOp(d!.H,d,Px,oldd,mu);
end
); # IsNewIndecomposable (toplevel)
##P Removes the columns for <Px> in <d>
InstallMethod(RemoveIndecomposableOp,
"for a decomposition matrix and a partition",
[IsDecompositionMatrix,IsList],
function(d,mu) local r, c;
c:=Position(d!.cols, mu);
if c=fail then
Print("RemoveIndecomposable(<d>,<mu>), <mu> is not listed in <d>\n");
else Unbind(d!.d[c]);
fi;
end
); # RemoveIndecomposable
### Prints a list of the indecomposable missing from d
InstallMethod(MissingIndecomposables,
"missing entries of a decomposition matrix",
[IsDecompositionMatrix],
function(d) local c, missing;
missing:=List([1..Length(d!.cols)], c->not IsBound(d!.d[c]) );
if true in missing then
Print("The following projectives are missing from <d>:\n ");
for c in [Length(missing),Length(missing)-1..1] do
if missing[c] then Print(" ", d!.cols[c]); fi;
od;
Print("\n");
fi;
end
); # MissingIndecomposables
## When no ordering is supplied then rows are ordered first by length and
## then lexicographically. The rows and columns may also be explicitly
## assigned.
## Usage:
## DecompositionMatrix(H, n [,ordering]);
## DecompositionMatrix(H, <file>) ** force Specht() to read <file>
InstallOtherMethod(DecompositionMatrix,"for an algebra and an integer",
[IsAlgebraObj,IsInt],
function(H,n) local Px, d, c;
d:=FindDecompositionMatrix(H,n);
if d=fail then
if H!.p>0 and n>2*H!.e then ## no point even trying
Print("# This decomposition matrix is not known; use ",
"CalculateDecompositionMatrix()\n# or ",
"InducedDecompositionMatrix() to calculate with this matrix.",
"\n");
return d;
fi;
if not IsSchur(H) then c:=ERegularPartitions(H!.e,n);
else c:=Partitions(n);
fi;
d:=DecompositionMatrix(H,Partitions(n),c,true);
fi;
if ForAny([1..Length(d!.cols)],c->not IsBound(d!.d[c])) then
for c in [1..Length(d!.cols)] do
if not IsBound(d!.d[c]) then
Px:=MakeSpechtOp(Module(H,"P",1,d!.cols[c]),true);
if Px<>fail then AddIndecomposable(d,Px,false);
else Print("# Projective indecomposable P(",
TightStringList(d!.cols[c]),") not known.\n");
fi;
fi;
od;
Store(d,n);
fi;
if d<>fail then ## can't risk corrupting the internal matrix lists
d:=CopyDecompositionMatrix(d);
fi;
return d;
end
);
InstallOtherMethod(DecompositionMatrix,
"for an algebra, an integer and an ordering",
[IsAlgebraObj,IsInt,IsFunction],
function(H,n,ord)
H!.Ordering := ord;
return DecompositionMatrix(H,n);
end
);
InstallOtherMethod(DecompositionMatrix,"for an algebra and a filename",
[IsAlgebraObj,IsString],
function(H,file) local d;
d:=ReadDecompositionMatrix(H,file,false);
if d<>fail and not IsBound(d!.matname) then ## override and copy
Store(d,Sum(d!.cols[1]));
MissingIndecomposables(d);
fi;
if d<>fail then ## can't risk corrupting the internal matrix lists
d:=CopyDecompositionMatrix(d);
fi;
return d;
end
);
InstallOtherMethod(DecompositionMatrix,
"for an algebra, a filename and an ordering",
[IsAlgebraObj,IsString,IsFunction],
function(H,file,ord)
H!.Ordering := ord;
return DecompositionMatrix(H,file);
end
); # DecompositionMatrix
#F Tries to calculate the decomposition matrix d_{H,n} from scratch.
## At present will return only those column indexed by the partitions
## of e-weight less than 2.
InstallMethod(CalculateDecompositionMatrix,"for an algebra and an integer",
[IsAlgebraObj,IsInt],
function(H,n) local d, c, Px;
if not IsSchur(H) then c:=ERegularPartitions(H!.e,n);
else c:=Partitions(n);
fi;
d:=DecompositionMatrix(H,Partitions(n),c,true);
for c in [1..Length(d!.cols)] do
if not IsBound(d!.d[c]) then
Px:=MakeSpechtOp(Module(H,"P",1,d!.cols[c]),true);
if Px<>fail then AddIndecomposable(d,Px,false);
else Print("# Projective indecomposable P(",
TightStringList(d!.cols[c]),") not known.\n");
fi;
fi;
od;
return d;
end
); # CalculateDecompositionMatrix
#F Returns a crystallized decomposition matrix
InstallMethod(CrystalDecompositionMatrix,"for an algebra and an integer",
[IsAlgebraObj,IsInt],
function(H,n) local d, Px, c;
if not IsZeroCharacteristic(H) or IsSchur(H) then
Error("Crystal decomposition matrices are defined only ",
"for Hecke algebras\n with H!.p=0\n");
fi;
d:=ReadDecompositionMatrix(H,n,true);
if d<>fail then d:=CopyDecompositionMatrix(d);
else d:=DecompositionMatrix(H,
Partitions(n),ERegularPartitions(H!.e,n),false);
fi;
for c in [1..Length(d!.cols)] do
if not IsBound(d!.d[c]) then
AddIndecomposable(d,FindPq(H,d!.cols[c]),false);
fi;
od;
return d;
end
);
InstallMethod(CrystalDecompositionMatrix,
"for an algebra, an integer and an ordering",
[IsAlgebraObj,IsInt,IsFunction],
function(H,n,ord)
H!.Ordering := ord;
return CrystalDecompositionMatrix(H,n);
end
); # CrystalDecompositionMatrix
## Given a decomposition matrix induce it to find as many columns as
## possible of the next higher matrix using simple minded induction.
## Not as simple minded as it was originally, as it now tries to use
## Schaper's theorem [JM2] to break up troublesome projectives. The
## function looks deceptively simple because all of the work is now
## done by IsNewIndecomposable().
## Usage: InducedDecompositionMatrix(dn)
## in the second form new columns are added to d{n+1}.
InstallMethod(InducedDecompositionMatrix,"induce from decomposition matrix",
[IsDecompositionMatrix],
function(d)
local newd, mu, nu, Px, Py, n,r, needNewline;
if IsCrystalDecompositionMatrix(d)
then Error("InducedDecompositionMatrix(d): ",
"<d> must be a decomposition matrix.");
fi;
needNewline := false;
n:=Sum(d!.rows[1])+1;
if n>8 then ## print dots to let the user
PrintTo("*stdout*","# Inducing."); ## know something is happening.
needNewline := true;
fi;
nu:=Partitions(n);
if IsSchur(d!.H) then
newd:=DecompositionMatrix(d!.H, nu, nu, true);
else newd:=DecompositionMatrix(d!.H, nu,
ERegularPartitions(d!.H!.e,n),true);
fi;
## add any P(mu)'s with EWeight(mu)<=1 or P(mu)=S(mu) <=> S(mu')=D(mu')
for mu in newd!.cols do
if EWeight(d!.H!.e,mu)<=1 then
AddIndecomposable(newd,
MakeSpechtOp(Module(d!.H,"P",1,mu),true),false);
elif IsSimpleModule(d!.H,ConjugatePartition(mu)) then
AddIndecomposable(newd, Module(d!.H,"S",1,mu),false);
fi;
od;
## next we r-induce all of the partitions in d so we can just add
## them up as we need them later.
## (note that this InducedModule() is Specht()'s and not the generic one)
d!.ind:=List(d!.rows, mu->List([0..d!.H!.e-1],
r->RInducedModule(d!.H,Module(d!.H,"S",1,mu),d!.H!.e,r)));
if n<9 then n:=Length(d!.cols)+1; fi; ## fudge for user friendliness
for mu in [1..Length(d!.cols)] do
if IsBound(d!.d[mu]) then
for r in [1..d!.H!.e] do ## really the e-residues; see ind above
## Here we calculate InducedModule(P(mu),H.e,r).
Px:=Sum([1..Length(d!.d[mu].parts)],
nu->d!.d[mu].coeffs[nu]*d!.ind[d!.d[mu].parts[nu]][r]);
if IsNewIndecomposableOp(d!.H,newd,Px,d,[fail]) then
if IsERegular(Px!.H!.e,Px!.parts[Length(Px!.parts)]) then
# can apply MullineuxMap
nu:=ConjugatePartition(Px!.parts[1]);
if nu<>MullineuxMap(d!.H!.e,Px!.parts[Length(Px!.parts)]) then
## wrong image under the Mullineux map
BUG("Induce", 7, "nu = ", nu, ", Px = ", Px);
else ## place the Mullineux image of Px as well
AddIndecomposable(newd,MullineuxMap(Px),false);
fi;
fi;
AddIndecomposable(newd,Px,false);
fi;
od;
if mu mod n = 0 then PrintTo("*stdout*","."); needNewline := true; fi;
fi;
od;
Unbind(d!.ind); Unbind(d!.simples); ## maybe we should leave these.
if needNewline then Print("\n"); fi;
MissingIndecomposables(newd);
return newd;
end
); # InducedDecompositionMatrix
#F Returns the inverse of (the e-regular part of) d. We invert the matrix
## 'by hand' because the matrix routines can't handle polynomial entries.
## This should be much faster than it is???
InstallMethod(InvertDecompositionMatrix,"for a decomposition matrix",
[IsDecompositionMatrix],
function(d) local inverse, c, r;
inverse:=DecompositionMatrix(d!.H,d!.cols,d!.cols,
not IsCrystalDecompositionMatrix(d));
## for some reason I can't put this inside the second loop (deleting
## the first because d.inverse is not updated this way around...).
for c in [1..Length(inverse!.cols)] do
Invert(d,d!.cols[c]);
od;
for c in [1..Length(inverse!.cols)] do
if IsBound(d!.inverse[c]) then
inverse!.d[c]:=rec(parts:=[], coeffs:=[]);
for r in [1..c] do
if IsBound(d!.inverse[r]) and c in d!.inverse[r].parts then
Add(inverse!.d[c].parts,r);
Add(inverse!.d[c].coeffs,
d!.inverse[r].coeffs[Position(d!.inverse[r].parts,c)]);
fi;
od;
if inverse!.d[c]=rec(parts:=[], coeffs:=[]) then Unbind(inverse!.d[c]); fi;
fi;
od;
inverse!.matname:="Inverse matrix";
return inverse;
end
); # InvertDecompositionMatrix
#P Saves a full decomposition matrix; actually, only the d, rows, and cols
## records components are saved and the rest calculated when read back in.
## The decomposition matrices are saved in the following format:
## A_Specht_Decomposition_Matrix:=rec(
## d:=[[r1,...,rk,d1,...dk],[...],...[]],rows:=[..],cols:=[...]);
## where r1,...,rk are the rows in the first column with corresponding
## decomposition numbers d1,...,dk (if di is a polynomial then it is saved
## as a list [di.valuation,<sequence of di.coffcients]; in particular we
## don't save the polynomial name).
## Usage: SaveDecompositionMatrix(<d>)
## or SaveDecompositionMatrix(<d>,<filename>);
InstallMethod(SaveDecompositionMatrix,
"for a decomposition matrix and a filename",
[IsDecompositionMatrix,IsString],
function(d,file)
local TightList,n,SaveDm,size, r, c, str, tmp;
n:=Sum(d!.rows[1]);
size:=SizeScreen(); ## SizeScreen(0 shouldn't affect PrintTo()
SizeScreen([80,40]); ## but it does; this is our protection.
TightList:=function(list) local l, str;
str:="[";
for l in list{[1..Length(list)-1]} do
if IsList(l) then
l:=TightList(l);
str:=Concatenation(str,l);
else str:=Concatenation(str,String(l));
fi;
str:=Concatenation(str,",");
od;
l:=list[Length(list)];
if IsList(l) then
l:=TightList(l);
str:=Concatenation(str,l);
else str:=Concatenation(str,String(l));
fi;
return Concatenation(str,"]");
end;
if d=fail then Error("SaveDecompositionMatrix(<d>), d=fail!!!\n"); fi;
SaveDm:=function(file)
AppendTo(file,"## This is a GAP library file generated by \n## Hecke ",
d!.H!.info.version, "\n\n## This file contains ");
if IsBound(d!.matname) then
AppendTo(file,"a(n) ", d!.matname, " for n = ", Sum(d!.rows[1]),"\n");
else
if IsCrystalDecompositionMatrix(d) then AppendTo(file,"the crystallized "); fi;
AppendTo(file,"the decomposition matrix\n## of the ");
if not IsSchur(d!.H) then
if d!.H!.e<>d!.H!.p then AppendTo(file,"Hecke algebra of ");
else AppendTo(file,"symmetric group ");
fi;
else AppendTo(file,"q-Schur algebra of ");
fi;
AppendTo(file,"Sym(",n,") over a field\n## ");
if d!.H!.p=0 then AppendTo(file,"of characteristic 0 with ");
elif d!.H!.p=d!.H!.e then AppendTo(file,"of characteristic ",d!.H!.p,".\n\n");
else AppendTo(file,"with HeckeRing = ", d!.H!.HeckeRing, ", and ");
fi;
if d!.H!.p<>d!.H!.e then AppendTo(file,"e=", d!.H!.e, ".\n\n");fi;
fi;
AppendTo(file,"A_Specht_Decomposition_Matrix:=rec(\nd:=[");
str:="[";
for c in [1..Length(d!.cols)] do
if not IsBound(d!.d[c]) then AppendTo(file,str,"]");
else
for r in d!.d[c].coeffs do
if IsLaurentPolynomial(r) then
tmp:=ShallowCopy(CoefficientsOfLaurentPolynomial(r));
AppendTo(file,str,"[",tmp[2],",",TightStringList(tmp[1]),"]");
else AppendTo(file,str,r);
fi;
str:=",";
od;
for r in d!.d[c].parts do
AppendTo(file,str,r);
od;
AppendTo(file,"]");
str:=",[";
fi;
od;
AppendTo(file,"],rows:=",TightList(d!.rows));
AppendTo(file,",cols:=",TightList(d!.cols));
if IsCrystalDecompositionMatrix(d) then
AppendTo(file,",crystal:=true");
fi;
if IsBound(d!.matname) then AppendTo(file,",matname:=\"",d!.matname,"\""); fi;
AppendTo(file,");\n");
end;
## the actual saving of d
SaveDm(file);
## now we put d into DecompositionMatrices
if not IsBound(d!.matname) then Store(d,n); fi;
SizeScreen(size); # restore screen.
end
);
InstallMethod(SaveDecompositionMatrix,"for a decomposition matrix",
[IsDecompositionMatrix],
function(d) local n,file;
if d!.H!.HeckeRing="unknown" then
Print("SaveDecompositionMatrix(d): \n the base ring of the Hecke ",
"algebra is unknown.\n You must set <d>.H.HeckeRing in ",
"order to save <d>.\n");
return;
fi;
n:=Sum(d!.rows[1]);
if IsBound(d!.matname) then
file:=Concatenation(d!.H!.HeckeRing,".",d!.matname{[1]},String(n));
elif not IsCrystalDecompositionMatrix(d) then
file:=Concatenation(d!.H!.HeckeRing,".",String(n));
else ## crystallized decomposition matrix
file:=Concatenation("e", String(d!.H!.e), "crys.", String(n));
fi;
SaveDecompositionMatrix(d,file);
end
);# SaveDecompositionMatrix()
#F Returns the 'adjustment matrix' [J] for <d> and <dp>. ie the
## matrix <a> such that <dp>=<a>*<d>.
InstallMethod(AdjustmentMatrix,"for two decomposition matrices",
[IsDecompositionMatrix,IsDecompositionMatrix],
function(dp,d) local ad, c, x;
if d!.cols<>dp!.cols or d!.rows<>dp!.rows then return fail; fi;
ad:=DecompositionMatrix(dp!.H,dp!.cols,dp!.cols,true);
ad!.matname:="Adjustment matrix";
c:=1;
while ad<>fail and c<=Length(d!.cols) do
if IsBound(dp!.cols[c]) then
x:=MakePIMSpechtOp(dp, dp!.cols[c]);
x!.H:=d!.H;
x:=MakePIMOp(d,x);
if x=fail then ad:=fail;
else AddIndecomposable(ad,x,false);
fi;
fi;
c:=c+1;
od;
return ad;
end
); # AdjustmentMatrix
## Returns the a GAP matrix for the decomposition matrix <d>. Note that
## the rows and columns and <d> are ordered according to H.info.Ordering.
InstallMethod(MatrixDecompositionMatrix,"decomposition matrix -> matrix",
[IsDecompositionMatrix],
function(d) local r,c, rows, cols, m;
rows:=StructuralCopy(d!.rows);
if d!.H!.Ordering<>Lexicographic then
Sort(rows,d!.H!.Ordering);
rows:=List(rows,r->Position(d!.rows,r));
else rows:=[Length(rows),Length(rows)-1..1];
fi;
cols:=StructuralCopy(d!.cols);
if d!.H!.Ordering<>Lexicographic then
Sort(cols,d!.H!.Ordering);
cols:=List(cols,r->Position(d!.cols,r));
else cols:=[Length(cols),Length(cols)-1..1];
fi;
m:=[];
for r in [1..Length(rows)] do
m[r]:=[];
for c in [1..Length(cols)] do
if IsBound(d!.d[cols[c]]) and rows[r] in d!.d[cols[c]].parts then
m[r][c]:=d!.d[cols[c]].coeffs[Position(d!.d[cols[c]].parts,rows[r])];
else m[r][c]:=0;
fi;
od;
od;
return m;
end
);
## Given a GAP matrix this function returns a Specht decomposition matrix.
## H = Specht() record
## m = matrix: either #reg x #reg, #parts x #reg, or #parts x #parts
## n = Sym(n)
InstallMethod(DecompositionMatrixMatrix,"matrix -> decomposition matrix",
[IsAlgebraObj,IsMatrix,IsInt],
function(H,m,n) local r, c, rows, cols, d;
rows:=Partitions(n);
cols:=ERegularPartitions(H,n);
if Length(rows)<>Length(m) then rows:=cols; fi;
if Length(cols)<>Length(m[1]) then cols:=rows; fi;
if Length(rows)<>Length(m) or Length(cols)<>Length(m[1]) then
Print("# usage: DecompositionMatrixMatrix(H, m, n)\n",
" where m is a matrix of an appropriate size.\n");
return fail;
fi;
if ForAll(m, r->ForAll(r, c->IsInt(c) )) then
d:=DecompositionMatrix(H,StructuralCopy(rows),StructuralCopy(cols),true);
else ## presumably crystalized
d:=DecompositionMatrix(H,StructuralCopy(rows),StructuralCopy(cols),false);
fi;
## now we order the rows and columns properly
if H!.Ordering<>Lexicographic then Sort(rows, H!.Ordering);
else rows:=rows{[Length(rows),Length(rows)-1..1]};
fi;
rows:=List(d!.rows, r->Position(rows, r) );
if H!.Ordering<>Lexicographic then Sort(cols, H!.Ordering);
else cols:=cols{[Length(cols),Length(cols)-1..1]};
fi;
cols:=List(d!.cols, c->Position(cols, c) );
for c in [1..Length(cols)] do
d!.d[c]:=rec(parts:=[], coeffs:=[]);
for r in [1..Length(rows)] do
if m[rows[r]][cols[c]]<>0*m[rows[r]][cols[c]] then ## maybe polynomial
Add(d!.d[c].parts, r);
Add(d!.d[c].coeffs, m[rows[r]][cols[c]]);
fi;
od;
if d!.d[c].parts=[] then Unbind(d!.d[c]); fi;
od;
return d;
end
); # DecompositionMatrixMatrix
## OPERATIONS OF FORMER SPECHT RECORD ##########################################
## The following two functions are used by P(), and elsewhere.
## generate the hook (k,1^n-k) - as a list - where k=arg
## actually not quite a hook since if arg is a list (n,k1,k2,...)
## this returns (k1,k2,...,1^(n-sum k_i))
InstallMethod(HookOp,"for an integer and a list of lists",[IsInt,IsList],
function(n,K) local k, i;
k:=Sum(K);
if k < n then Append(K, List([1..(n-k)], i->1));
elif k > n then Error("hook, partition ", k, " bigger than ",n, "\n");
fi;
return K;
end
); #Hook
InstallMethod(DoubleHook,"for four integers",[IsInt,IsInt,IsInt,IsInt],
function(n,x,y,a) local s, i;
s:=[x];
if y<>0 then Add(s,y); fi;
if a<>0 then Append(s, List([1..a],i->2)); fi;
i:=Sum(s);
if i < n then
Append(s, List([1..n-i], i->1));
return s;
elif i=n then return s;
else return [];
fi;
end
); #DoubleHook
#### RENAMED Omega -> HeckeOmega
## Returns p(n) - p(n-1,1) + p(n-2,1^2) - ... + (-1)^(n-1)*p(1^n).
## So, S(mu)*Omega(n) is the linear combination of the S(nu)'s where
## nu is obtained by wrapping an n-hook onto mu and attaching the
## sign of the leg length.
InstallMethod(HeckeOmega,"for an algebra, a string and an integer",
[IsAlgebraObj,IsString,IsInt],
function(H,module,n)
return Module(H,module,List([1..n],x->(-1)^(x)),
List([1..n],x->Hook(n,x)));
end
); #HeckeOmega
## MODULES #####################################################################
InstallMethod(Module,"create new module",[IsAlgebraObj,IsString,IsList,IsList],
function(H,m,c,p)
local module;
module := rec(H:=H,module:=m,coeffs:=c,parts:=p);
if m = "S" and not IsSchur(H) then Objectify(HeckeSpechtType,module);
elif m = "P" and not IsSchur(H) then Objectify(HeckePIMType,module);
elif m = "D" and not IsSchur(H) then Objectify(HeckeSimpleType,module);
elif m = "Sq" and not IsSchur(H) then Objectify(HeckeSpechtFockType,module);
elif m = "Pq" and not IsSchur(H) then Objectify(HeckePIMFockType,module);
elif m = "Dq" and not IsSchur(H) then Objectify(HeckeSimpleFockType,module);
elif m = "W" or m = "S" then Objectify(SchurWeylType,module); module!.module:="W";
elif m = "P" then Objectify(SchurPIMType,module);
elif m = "F" or m = "D" then Objectify(SchurSimpleType,module); module!.module:="F";
elif m = "Wq" or m = "Sq" then Objectify(SchurWeylFockType,module); module!.module:="Wq";
elif m = "Pq" then Objectify(SchurPIMFockType,module);
elif m = "Fq" or m = "Dq" then Objectify(SchurSimpleFockType,module); module!.module:="Fq";
fi;
return module;
end
);
InstallMethod(Module,"create new module",[IsAlgebraObj,IsString,IsInt,IsList],
function(H,m,c,p)
return Module(H,m,[c],[p]);
end
);
InstallMethod(Module,"create new module",[IsAlgebraObj,IsString,IsLaurentPolynomial,IsList],
function(H,m,c,p)
return Module(H,m,[c],[p]);
end
);
## Takes two lists, one containing coefficients and the other the
## corresponding partitions, and orders them lexicographically collecting
## like terms on the way. We use a variation on quicksort which is
## induced by the lexicographic order (if parts contains partitions of
## different integers this can lead to an error - which we don't catch).
InstallMethod(Collect,"utility for module generation",
[IsAlgebraObj,IsString,IsList,IsList],
function(H, module, coeffs, parts)
local newx, i, Place, Unplace, places;
## inserting parts[i] into places. if parts[i]=[p1,p2,...] then
## we insert it into places at places[p1][[p2][...] stopping
## at the fist empty position (say places[p1], or places[p1][p2]
## etc.). Here we are trying to position parts[i] at
## places[p1]...[pd]. Actually, we just insert i rather than
## parts[i] and if we find that parts[i]=parts[j] for some j then
## we set coeffs[i]:=coeffs[i]+coeffs[j] and don't place j.
Place:=function(i, places, d) local t;
if IsInt(places) then
t:=places;
if parts[t]=parts[i] then coeffs[t]:=coeffs[t]+coeffs[i];
else
places:=[];
places[parts[t][d]]:=t;
if parts[i][d]<>parts[t][d] then places[parts[i][d]]:=i;
else places:=Place(i, places, d);
fi;
fi;
elif places=[] or not IsBound(places[parts[i][d]]) then
# must be a list
places[parts[i][d]]:=i;
else places[parts[i][d]]:=Place(i, places[parts[i][d]], d+1);
fi;
return places;
end;
Unplace:=function(places) local p, newp, np;
newp:=[[],[]];
for p in places do
if IsInt(p) then if coeffs[p]<>0*coeffs[p] then
Add(newp[1], coeffs[p]);
Add(newp[2], StructuralCopy(parts[p])); fi;
else
np:=Unplace(p);
Append(newp[1], np[1]);
Append(newp[2], np[2]);
fi;
od;
return newp;
end;
if parts=[] then return Module(H,module,0,[]);
elif Length(parts)=1 then return Module(H,module,coeffs,parts);
else places:=[];
for i in [1..Length(parts)] do places:=Place(i, places, 1); od;
newx:=Unplace(places);
if newx=[[],[]] then return Module(H,module,0,[]);
else return Module(H,module,newx[1],newx[2]);
fi;
fi;
end ## H.operations.Collect
);
## MODULE CONVERSION ###########################################################
## Finally the conversion functions S(), P() and D(). All take
## a linear combination of Specht modules and return corresponding
## linear combinations of Specht, indecomposables, and simples resp.
## If they have a problem they return false and print an error
## message unless silent=true.
InstallMethod(MakeSpechtOp,"S()->S()",[IsHeckeSpecht,IsBool],
function(x,silent) return x; end
);
InstallMethod(MakeSpechtOp,"S[q]()->S[q]()",[IsDecompositionMatrix,IsHeckeSpecht],
function(d,x) return x; end
);
## Here I only allow for linear combinations of projectives which
## have non-negative coefficients; the reason for this is that I
## can't see how to do it otherwise. The problem is that in the
## Grothendieck ring there are many ways to write a given linear
## combination of Specht modules (or PIMs).
InstallMethod(MakePIMOp,"S()->P()",[IsHeckeSpecht,IsBool],
function(x,silent) local proj, tmp;
if x=fail or x=0*x then return x;
elif x!.parts=[[]] then return Module(x!.H,"P",x!.coeffs[1],[]);
fi;
proj:=Module(x!.H,"P",0,[]);
while x<>fail and x<>0*x and
( IsSchur(x!.H) or IsERegular(x!.H!.e,x!.parts[Length(x!.parts)]) ) do
proj:=proj+Module(x!.H,"P",x!.coeffs[Length(x!.parts)],
x!.parts[Length(x!.parts)]);
tmp:=MakeSpechtOp(
Module(x!.H,"P",-x!.coeffs[Length(x!.parts)],
x!.parts[Length(x!.parts)]),true);
if tmp<>fail then x:=x+tmp; else x:=fail; fi;
od;
if x=fail or x<>0*x then
if not silent then
Print("# P(<x>), unable to rewrite <x> as a sum of projectives\n");
fi;
else return proj;
fi;
return fail;
end
);
InstallMethod(MakePIMOp,"S[q]()->P[q]()",[IsDecompositionMatrix,IsHeckeSpecht],
function(d,x) local nx, r, c, P, S;
if x=fail or x=0*x then return x; fi;
if IsCrystalDecompositionMatrix(d) then P:="Pq"; S:="Sq";
else P:="P"; S:="S";
fi;
nx:=Module(x!.H,P,0,[]);
while x<>fail and x<>0*x do
c:=Position(d!.cols,x!.parts[Length(x!.parts)]);
if c=fail or not IsBound(d!.d[c]) then return fail; fi;
nx:=nx+Module(x!.H,P,x!.coeffs[Length(x!.parts)],d!.cols[c]);
x:=x+Module(x!.H,S,-x!.coeffs[Length(x!.parts)]*d!.d[c].coeffs,
List(d!.d[c].parts,r->d!.rows[r]));
od;
return nx;
end
);
InstallMethod(MakeSimpleOp,"S()->D()",[IsHeckeSpecht,IsBool],
function(x,silent) local y, d, simples, r, c;
if x=fail or x=0*x then return x;
elif x!.parts=[[]] then return Module(x!.H,"D",x!.coeffs[1],[]);
fi;
d:=KnownDecompositionMatrix(x!.H,Sum(x!.parts[1]));
if d<>fail then
y:=MakeSimpleOp(d,x);
if y<>fail then return y; fi;
fi;
## since that didn't work, we use the LLT algorithm when IsBound(H.Pq)
if IsZeroCharacteristic(x!.H) and not IsSchur(x!.H) then
return Sum([1..Length(x!.parts)],
r->x!.coeffs[r]*Specialized(FindSq(x!.H,x!.parts[r])));
fi;
# next, see if we can calculate the answer.
d:=Concatenation(x!.H!.HeckeRing,"D");
# finally, we can hope that only partitions of e-weight<2 appear in x
r:=1; simples:=Module(x!.H,"D",0,[]);
while simples<>fail and r <= Length(x!.parts) do
if IsSimpleModule(x!.H, x!.parts[r]) then
simples:=simples+Module(x!.H,"D",x!.coeffs[r], x!.parts[r]);
elif IsERegular(x!.H!.e,x!.parts[r]) and EWeight(x!.H!.e,x!.parts[r])=1
then
y:=Module(x!.H,"S",1,ECore(x!.H!.e,x!.parts[r]))
* HeckeOmega(x!.H,"S",x!.H!.e);
c:=Position(y!.parts,x!.parts[r]); ## >1 since not IsSimpleModule
simples:=simples
+Module(x!.H,"D",[1,1],[y!.parts[c],y!.parts[c-1]]);
#### elif IsBound(x.operations.(d)) then ## FIXME not needed anymore?
#### simples:=simples+x.operations.(d)(x.parts[r]);
else simples:=fail;
fi;
r:=r+1;
od;
if simples=fail and not silent then
Print("# D(<x>), unable to rewrite <x> as a sum of simples\n");
return fail;
else return simples;
fi;
end
);
InstallMethod(MakeSimpleOp,"S[q]()->D[q]()",[IsDecompositionMatrix,IsHeckeSpecht],
function(d,x) local nx, y, r, rr, c, D, core;
if x=fail or x=0*x then return x; fi;
if IsCrystalDecompositionMatrix(d) then D:="Dq"; else D:="D"; fi;
nx:=Module(x!.H,D,0,[]);
for y in [1..Length(x!.parts)] do
r:=Position(d!.rows, x!.parts[y]);
if r=fail then return fail; fi;
core:=ECore(x!.H!.e,x!.parts[y]);
c:=Length(d!.cols);
while c>0 and d!.cols[c]>=x!.parts[y] do
if IsBound(d!.d[c]) then
rr:=Position(d!.d[c].parts,r);
if rr<>fail then nx:=nx+Module(x!.H,D,
x!.coeffs[y]*d!.d[c].coeffs[rr],d!.cols[c]);
fi;
elif ECore(x!.H!.e,d!.cols[c])=core then return fail;
fi;
c:=c-1;
od;
od;
return nx;
end
);
## The P->S functions are quite involved.
#F Writes x, which is a sum of indecomposables, as a sum of S(nu)'s if
## possible. We first check to see if the decomposition matrix for x is
## stored somewhere, and if not we try to calculate what we need. If we
## can't do this we return false.
InstallMethod(MakeSpechtOp,"P()->S()",[IsHeckePIM,IsBool],
function(x,silent) local y, c, d, mu, specht;
if x=fail or x=0*x then return x;
elif x!.parts=[[]] then return Module(x!.H,"S",x!.coeffs[1],[]);
fi;
d:=KnownDecompositionMatrix(x!.H,Sum(x!.parts[1]));
if d<>fail then
y:=MakeSpechtOp(d,x);
if y<>fail then return y; fi;
fi;
## since that didn't work, we use the LLT algorithm when
## IsBound(H.Pq)
if IsZeroCharacteristic(x!.H) then
if not IsSchur(x!.H) or ForAll(x!.parts, c->IsERegular(x!.H!.e,c)) then
return Sum([1..Length(x!.parts)],c->
x!.coeffs[c]*Specialized(FindPq(x!.H,x!.parts[c])));
fi;
fi;
d:=Concatenation(x!.H!.HeckeRing,"S");
mu:=1; specht:=Module(x!.H,"S",0,[]);
while specht<>fail and mu<=Length(x!.parts) do
if IsSimpleModule(x!.H,ConjugatePartition(x!.parts[mu])) then
--> --------------------
--> maximum size reached
--> --------------------
[ Seitenstruktur0.175Drucken
]
|
2026-03-28
|