Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/GAP/pkg/hecke/gap/   (Algebra von RWTH Aachen Version 4.15.1©)  Datei vom 29.7.2024 mit Größe 134 kB image not shown  

Quelle  specht.gi   Sprache: unbekannt

 
Quellsprache: Binärcode.gi aufgebrochen in jeweils 16 ZeichenUnknown {[0] [0] [0]}zum Wurzelverzeichnis wechseln

#######################################################################
##  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

--> --------------------

[ zur Elbe Produktseite wechseln0.74Quellennavigators  ]