Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


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  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge