(* :Title: Weyl.m *)

(* :Context: Projects`Weyl.m *)

(* :Author: Donald E. Taylor *)

(* :Summary:
   This package defines functions to compute with finite Weyl groups.
   It uses special properties of Weyl groups whenever it can and thus
   avoids doing general group theory.
*)

(* :Copyright: © 1999 by D. E. Taylor *)

(* :Package Version: 1.0 *)

(* :Mathematica Version: 3.0 *)

(* :History:
   Version 1.0 September 1999
*)

(* :Keywords: Weyl group, Cartan matrix, Lie algebra, 
   highest weight module, reflection *)

(* :Sources:
   N. Bourbaki, Groupes et algebres de Lie, Chapitres 4-6, Hermann, 1968.
   H. Freudenthal and H. de Vries, Linear Lie groups, Academic Press, 1969.
   J.F. Humphreys, Introduction to Lie algebras and representation theory,
   Springer Verlag, 1972.
   R.V. Moody and J. Patera, Fast recursion formula for weight multiplicities,
   Bull. Amer. Math. Soc. 7 (1982), 237-242.
   J. Stembridge, A Maple package for root systems and
   Coxeter groups. Maple Share Library, 1998.
*)

(* :Warnings:
  The package is restricted to finite Weyl groups and the functions are not
  guaranteed to work with Cartan matrices of types H3, H4 and I2.
*)

(* :Limitations:
   The function CoxeterForm is designed to work with the Cartan matrices
   generated internally by this package and will not necessarily return
   the correct result for user-defined Cartan matrices.  The functions
   which depend on CoxeterForm are OrbitLength, WeylDimension and
   WeightMultiplicity.
*)

(* :Discussion:
   A (finite) Weyl group is defined by its Cartan matrix.  In this package 
   we do not generate elements of the group itself but refer back to the 
   Cartan matrix and the basic reflections which it defines.  The roots, 
   weights and reflections are written with respect to the basis of simple 
   roots determined by the Cartan matrix.
     The primary goal of the package is to do simple weight space 
   calculations.
*)

(* :Requirements:
   none
*)

(* :Examples:
   c = CartanMatrix["G",2]
   fw = FundamentalWeights[c]
   WeylDimension[c,fw[[1]]+fw[[2]]
   WeightMultiplicity[c,fw[[1]]+fw[[2]],fw[[1]]] 
*)

BeginPackage["Projects`Weyl`"]

(* usage messages for the exported functions and the context itself *)

Weyl::usage = 
    "This package deals with finite Weyl groups only.  Coxeter groups
of types H and I are not fully supported"

CartanMatrix::usage = 
    "CartanMatrix[type,rank] returns the Cartan matrix of the given
(simple) type and rank"

MatrixBlocks::usage =
    "MatrixBlocks[M] returns a partition of {1..Length[n]} representing
the connected components of the graph defined by joining i to j whenever
i > j and M[[i,j]] != 0"

CartanType::usage =
    "CartanType[C] returns a list of pairs consisting of the string type
of each component of C together with the indices giving the location of
the component in C"

WeylOrder::usage =
    "WeylOrder[C] is the order of the Weyl group with Cartan matrix C"

Degrees::usage =
    "Degrees[C] returns the sorted list of degrees of the basic invariants
of the Weyl group with Cartan matrix C"

Exponents::usage =
    "Exponents[C] returns the sorted list of exponents of the Weyl group
with Cartan matrix C"

NumberOfReflections::usage =
    "NumberOfReflections[C] is the number of reflections in the Weyl group
with Cartan matrix C"

PositiveRoots::usage =
    "PositiveRoots[C] returns the list of positive roots in the root system
determined by the Cartan matrix C"

Reflection::usage =
    "Reflection[C,k] returns the k-th simple reflection matrix corresponding
to the Cartan matrix C"

SimpleReflections::usage =
    "SimpleReflections[C] is the list of simple reflections of the
Weyl group with Cartan matrix C"

FundamentalWeights::usage =
    "FundamentalWeights[C] is the list of fundamental weights of the Weyl 
group with Cartan matrix C.  It coincides with the inverse of C"

DominantWeights::usage =
    "DominantWeights[C,lambda] is the list of dominant
weights <= lambda for the root system with Cartan matrix C,
where lambda is itself a dominant weight"

Orbit::usage =
    "Orbit[C,v] returns the orbit of the vector v under the
action of the Weyl group with Cartan matrix C.
    Orbit[C,v,subs] uses only the reflections indexed by subs"

OrbitLength::usage = 
    "OrbitLength[C,v,options] is the length of the orbit of the vector
v under the action of the Weyl group with Cartan matrix C.
    OrbitLength[C,v,subs,options] uses only the roots and reflections
indexed by subs"

Extended::usage = "Extended is an option for OrbitLength that specifies
whether or not to include -1 in the group defining the action"

Saturation::usage =
    "Saturation[C,lambda] returns all weights of the irreducible module
V(lambda) with highest weight lambda for the Lie algebra over the complex
numbers with Cartan matrix C"

CoxeterForm::usage =
    "CoxeterForm[C] returns a matrix describing the bilinear form
associated with the Cartan matrix C"

WeylDimension::usage =
    "WeylDimension[C,lambda] returns the dimension of the representation of
the irreducible module with highest weight lambda for the Lie algebra with
Cartan matrix C"

DominantRepresentative::usage =
    "DominantRepresentative[C,v] returns the unique element in the W-orbit
of v which lies in the fundamental Weyl chamber, where W is the Weyl
group with Cartan matrix C.
    DominantRepresentative[C,v,subs] uses only the roots and reflections
indexed by subs"

DominantSign::usage =
    "DominantSign[C,v] is the 0 if no element of the Weyl group W of the
Cartan matrix C fixes v, otherwise it is the sign of the unique element
of W that takes v to a dominant weight"

DominantQ::usage =
    "DominantQ[C,v] yields True if the vector v is a dominant weight with
respect to the Cartan matrix C"

WeightMultiplicity::usage =
    "WeightMultiplicity[C,lambda,mu] returns the dimension of the weight
space of mu in the irreducible module with heighest weight lambda for the
Lie algebra with Cartan matrix C"

TensorProduct::usage =
    "TensorProduct[C,mu,xi] is a list of pairs {m,lambda} where m is the
multiplicity of the irreducible module V(lambda) in the tensor product
of V(mu) and V(xi).  It is best if the dimension of V(mu) is small."

CoxeterNumber::usage =
    "CoxeterNumber[C] is the Coxeter number of the Weyl group with Cartan
matrix C"

(* error messages for the exported objects *)

CartanMatrix::badtype = "The type `` is not supported"

CartanType::inf = "Not a finite Weyl group"
CartanType::cycle = "Dynkin diagram of `` contains a cycle"

CoxeterForm::unrec =
    "`` is not an irreducible Cartan matrix"

Degrees::unknown = "Unknown Cartan type ``"

DominantWeights::notdom = "The weight `` is not dominant"
DominantWeights::incompat = "Matrix and weight have incompatible dimensions"

Begin["`Private`"]

CartanMatrix[ type_String, rank_Integer ] :=
  Module[{ m = Table[Switch[i-j,-1,-1,0,2,1,-1,_,0],{i,rank},{j,rank}] },
  (Switch[ type, 
  "A"|"a", Null,
  "B"|"b", m[[2,1]] = -2,
  "C"|"c", m[[1,2]] = -2,
  "D"|"d", m[[1,2]] = m[[2,1]] = 0;
           m[[1,3]] = m[[3,1]] = -1,
  "E"|"e", m[[1,2]] = m[[2,1]] = m[[2,3]] = m[[3,2]] = 0;
           m[[1,3]] = m[[3,1]] = m[[2,4]] = m[[4,2]] = -1,
  "F"|"f", m[[3,2]] = -2,
  "G"|"g", m[[2,1]] = -3,
  "H"|"h", m[[1,2]] = m[[2,1]] = -GoldenRatio,
  "I2"|"i2",
    m = With[ {z = Exp[2Pi I/rank],
    	       w = Exp[2Pi I(rank+1)/rank]+Exp[-2Pi I(rank+1)/rank]},
      Switch[ rank,
        3, {{2,-1},{-1,2}},
        4, {{2,-1},{-2,2}},
        6, {{2,-1},{-3,2}},
        _, If[EvenQ[rank],{{2,-1},{-2-z-z^-1,2}},{{2,w},{w,2}}]
      ]
    ],
  _,       Message[CartanMatrix::badtype,type];Return[$Failed]
  ];  m) /;
  (Switch[ type,
  "A"|"a", 1 <= rank,
  "B"|"b", 2 <= rank,
  "C"|"c", 2 <= rank,
  "D"|"d", 4 <= rank,
  "E"|"e", 6 <= rank && rank <= 8,
  "F"|"f", rank == 4,
  "G"|"g", rank == 2,
  _, True])
  ]

(* Non-crystallographic systems -- not implemented
Hn[ k_ ] :=
  Module[ {m = An[k]},
    m[[1,2]] = m[[2,1]] = -GoldenRatio;
    m
  ]

I2[ k_ ] :=
  With[ {z = Exp[2Pi I/k], w = Exp[2Pi I(k+1)/k]+Exp[-2Pi I(k+1)/k]},
    Switch[ k,
      3, {{2,-1},{-1,2}},
      4, {{2,-1},{-2,2}},
      6, {{2,-1},{-3,2}},
      _, If[EvenQ[k],{{2,-1},{-2-z-z^-1,2}},{{2,w},{w,2}}]
    ]
  ]
*)

(* Version 1
MatrixBlocks[M_?MatrixQ] := 
  Module[{i,j,k,l,p,n = Length[M],X},
    X = Range[n];
    For[ i = 2, i <= n, i++,
      For[ j = 1, j < i, j++,
        If[ M[[i,j]] == 0, Continue[] ];
        p = X[[{i,j}]];
        k = Min[p];
        l = Max[p];
        If[ k == l, Message[MatrixBlocks::cycle,M]; Return[$Failed] ];
        X = X /. { l->k };
        ]
      ];
    Map[Flatten[Position[X,#]]&,Union[X]]
    ]
*)

(* Version 2
MatrixBlocks[M_?MatrixQ] := 
  Module[{f,res},
    With[{n=Length[M],c=M},
      f[X_,p_] := With[{q = X[[p]]},With[{k=Min[q],l=Max[q]},
        If[k==l, Message[MatrixBlocks::cycle,c];Throw[$Failed], X/.{l->k}]]];
      res = Catch[Fold[f,Range[n],
        Select[Join @@ Table[Table[{i,j},{i,j-1}],{j,2,n}],
        c[[Sequence @@ #]] != 0&]]]
      ];
    If[res === $Failed, res, Map[Flatten[Position[res,#]]&,Union[res]]]
    ]
*)

MatrixBlocks[M_?MatrixQ] := 
  Module[{f,res},
    With[{n=Length[M]},
      f[X_,p_] := With[{q = X[[p]]},With[{k=Min[q],l=Max[q]}, X/.{l->k}]];
      res = Fold[f,Range[n],
        Select[Join @@ Table[{i,j},{j,2,n},{i,j-1}],
        M[[Sequence @@ #]] != 0&]]
      ];
    Flatten[Position[res,#]]& /@ Union[res]
    ]

CartanType[c_?MatrixQ] := 
    Map[simpleCartanType,Map[c[[#,#]]&,MatrixBlocks[c]]]

simpleCartanType[c_?MatrixQ] :=
  Module[{n=Length[c],edges,strong,gamma,deg,ends,fork,s,m},
    If[ n == 1, Return[{"A",1}] ];
    edges = Select[Join @@ Table[{i,j}, {i,n}, {j,n}],
        c[[Sequence @@ #]] < 0 &];
    If[ 2n != Length[edges]+2, Message[CartanType::cycle,c];Return[$Failed] ];
    strong = Select[edges,c[[Sequence @@ #]] < -1&];
    If[ Length[strong] > 1, Message[CartanType::inf];Return[$Failed] ];
    strong = Flatten[strong];
    m = If[ Length[strong] == 0, -1, c[[Sequence @@ strong]] ];
    With[{et = Transpose[edges]}, (* List of neighbours *)
      gamma = Last[et][[Flatten[Position[First[et],#]]]]& /@ Range[n]];
    deg = Length /@ gamma;
    ends = Flatten[Position[deg,1]];
    Switch[ Length[ends],
      2, If[ m == -1, Return[{"A",n}] ];
         s = Intersection[ends,strong];
         Switch[ Length[s],
           0, If[ n == 4 && m == -2, Return[{"F",4}] ],
           1, If[ m == -2,
               If[ strong[[1]] == s[[1]], Return[{"C",n}], Return[{"B",n}]],
               ],
           2, If[ m == -2, Return[{"C",2}] ];
              If[ m == -3, Return[{"G",2}] ]
           ],
      3, s = Length[Intersection[ ends,
               gamma[[First[Flatten[Position[deg,3]]]]] ]];
         If[ s == 1 && n < 9, Return[{"E",n}] ];
         If[ s > 1 && n > 3,  Return[{"D",n}] ]
      ];
    Message[CartanType::inf];
    $Failed
    ]

PositiveRoots[ c_?MatrixQ ] :=
  With[{n=Length[c]},
    With[{b=IdentityMatrix[n],
      t = Select[Join @@ Table[{i,j}, {i,1,n-1}, {j,i+1,n}],
          c[[Sequence @@ #]] < 0 &]},
    Join @@ allLayers[c,{b},Apply[Function[{x,y},b[[x]]+b[[y]]],t,{1}]]
  ]]

allLayers[ c_, layer_, {} ] := layer
allLayers[ c_, layer_, r_ ] := 
  Module[{f},
    With[{b=First[layer],h=Length[layer],ndx=Range[Length[c]]},
      f[R_,beta_] := Module[{bC = beta.c},
        Join[R,beta + b[[#]]& /@ Select[ndx,
          Function[i,With[{ip=bC[[i]],alpha=b[[i]]},
            (ip < 0 || (h > ip && beta[[i]] > ip &&
             MemberQ[layer[[h-ip]],beta-(ip+1)alpha])) &&
             FreeQ[R,beta+alpha] ]]]]]
      ];
    allLayers[c,Append[layer,r],Fold[f,{},r]]
  ]

Reflection[c_?MatrixQ, k_Integer] :=
  Module[{M = IdentityMatrix[Length[c]], t = Transpose[c]},
    M[[k]] = M[[k]] - t[[k]]; Transpose[M]
    ]
Reflection[c_?MatrixQ, lst_List] := Reflection[c,#]& /@ lst

SimpleReflections[c_?MatrixQ] := Reflection[c,Range[Length[c]]]

FundamentalWeights[c_?MatrixQ] := Inverse[c]

DominantWeights[ c_?MatrixQ, lambda_?VectorQ ] := 
  Module[{ R, dom, ndx, u, v },

  If[ Length[c] != Length[lambda],
    Message[DominantWeights::incompat]; Return[$Failed]];
  If[ Min[lambda . c] < 0,
    Message[DominantWeights::notdom,lambda]; Return[$Failed]];
  
  R = PositiveRoots[c];
  dom = { lambda };
  ndx = 0;
  While[ ndx < Length[dom], ndx++;
    u = dom[[ndx]];
    dom = Join[dom,Select[ (u - #&) /@ R,
      Function[v, Min[v . c ] >= 0 && FreeQ[dom,v]]]]
    ];
  dom
  ]

Orbit[ c_?MatrixQ, v_?VectorQ ] := orb[SimpleReflections[c],v]
Orbit[ c_?MatrixQ, v_?VectorQ, subs_List ] := 
                               orb[SimpleReflections[c][[subs]],v]

orb[ gen_List, v_?VectorQ ] := 
  Module[{o={v},ndx=0},
    While[ ndx < Length[o],
      ndx++;
      u = o[[ndx]];
      o = Join[o, Select[ (u . #&) /@ gen, FreeQ[o,#]& ]]
      ];
    o
    ]

Saturation[c_?MatrixQ,lambda_?VectorQ] :=
    Join @@ (Orbit[c,#]& /@ DominantWeights[c, lambda])

Options[OrbitLength] = {Extended->False}

OrbitLength[c_?MatrixQ, v_?VectorQ, subs_List, opts___?OptionQ ] :=
  Module[{u = DominantRepresentative[c,v,subs],
  	  b = v . CoxeterForm[c],d,extend,res},
    extend = Extended /. {opts} /. Options[OrbitLength];
    d = Select[subs, b[[#]] == 0& ];
    res = WeylOrder[c[[subs,subs]]]/WeylOrder[c[[d,d]]];
    If[extend && u != DominantRepresentative[c,-v,subs], 2 res, res]
    ]
OrbitLength[c_?MatrixQ, v_?VectorQ, opts___?OptionQ ] :=
  OrbitLength[c,v,Range[Length[c]],opts]

(* This relies completely on the form of the Cartan
matrix produced by this package *)
irrRootNorms[c_?MatrixQ] :=
  With[ { n = Length[c] },
    If[ c == Transpose[c], Table[1,{n}],
      If[ c[[1,2]] == -1,
        Switch[ c[[2,1]],
          -1, {1/2,1/2,1,1},
          -2, {1/2,Table[1,{n-1}]},
          -3, {1/2,3/2},
           _, Message[CoxeterForm::unrec, c ]; Return[$Failed]
          ],
        {1,Table[1/2,{n-1}]}
        ]
      ]
    ]

CoxeterForm[c_?MatrixQ] :=
  c . DiagonalMatrix[Flatten[Map[irrRootNorms,
        Map[c[[#,#]]&,MatrixBlocks[c]]]]]

WeylDimension[c_?MatrixQ, lambda_?VectorQ] := 
  With[{ R = PositiveRoots[c], b = CoxeterForm[c] },
    With[{ delta = (Plus @@ R) / 2 },
      With[{ s = (lambda+delta) . b, t = delta . b },
        Times @@ ((s . #)/(t . #)&) /@ R
        ]
      ]
    ]

DominantRepresentative[c_?MatrixQ, u_?VectorQ, subs_List] :=
  Module[{ i, v = u, vc = u . c },
    With[{ S = SimpleReflections[c] },
      While[ True,
        i = Select[ subs, vc[[#]] < 0&, 1 ];
        If[Length[i] == 0, Break[]];
        v = v . S[[First[i]]];
        vc = v . c
        ]
      ];
    v
    ]
DominantRepresentative[c_?MatrixQ, u_?VectorQ] :=
  DominantRepresentative[c,u,Range[Length[c]]]

DominantQ[c_?MatrixQ,v_?VectorQ] := Min[ v . c ] >= 0

DominantSign[c_?MatrixQ, u_?VectorQ] :=
  Module[{ i, v = u, vc = u . c, s },
    With[{ S = SimpleReflections[c], ndx = Range[Length[c]] },
      s = 1;
      While[ True,
        i = Select[ ndx, vc[[#]] < 0&, 1 ];
        If[Length[i] == 0, Break[]];
        v = v . S[[First[i]]];
        vc = v . c;
        s = -s
        ];
      s = If[ Length[Select[ndx, vc[[#]] == 0&, 1]] == 0, s, 0]
      ];
    s
    ]

(* From Stembridge *)
WeightMultiplicity[ c_?MatrixQ, lambda_?VectorQ, mu_?VectorQ ] :=
  Module[{u,v,wts,R,delta,n,ip,wl,mults,i,J,m,k,uu,j,orblen,ll,beta,ipb,ldip},
    u   = DominantRepresentative[c,mu];
    wts = DominantWeights[c,lambda];
    If[ FreeQ[wts,u], Return[0] ];

    wts = First /@ Sort[Thread[List[wts,Apply[Plus, wts, 1]]],
          Last[#1] > Last[#2]&];
    n  = First[First[Position[wts,u]]];
    ll = Range[Length[c]];
    ip = CoxeterForm[c];
    R  = PositiveRoots[c];
    delta = (Plus @@ R) / 2;
    ldip = (lambda+delta) . ip . (lambda+delta);
    wl = wts . c;
    mults[1] = 1;
    For[ i = 2, i <= n, i++,
      With[{alpha=wl[[i]]},
        J = Select[ll, alpha[[#]] == 0& ]];
      v = wts[[i]];
      m = 0;
      For[ k = 1, k <= Length[R], k++,
        beta = R[[k]];
        With[{alpha=beta . c},
          If[ Min[Map[alpha[[#]]&, J]] < 0, Continue[] ]];
        u = v + beta;
        uu = DominantRepresentative[c,u];
        If[ FreeQ[wts,uu], Continue[] ];
        j = First[First[Position[wts,uu]]];
        orblen = OrbitLength[c,beta,J,Extended->True];
        ipb = ip . beta;
        While[True,
          m += mults[j] orblen (u . ipb);
          u += beta;
          uu = DominantRepresentative[c,u];
          If[ FreeQ[wts,uu], Break[]];
          j = First[First[Position[wts,uu]]]
          ]
        ];
      mults[i] = m/(ldip - (v+delta).ip.(v+delta))
      ];
    mults[n]
    ]

(* Unfinished - from Stembridge
TensorProductWeights[c_?MatrixQ,u_?VectorQ,v_?VectorQ] :=
  Module[{wts,wl,cow,ip,coRoots,lb,n,i,k},
    ip = CoxeterForm[c];
    R = PositiveRoots[c];
    wts = DominantWeights[c,u+v];
    coRoots = Table[2 r[[i]]/(r[[i]] . ip . r[[i]]),{i,Length[c]}];
    cow = coRoots . c;
    wl = wts . c;
    
    ]
*)

TensorProduct[c_?MatrixQ,u_?VectorQ,v_?VectorQ] :=
  Module[{sat,delta,ndx,dr,mul,wts},
    delta = (Plus @@ PositiveRoots[c]) / 2;
    sat = Saturation[c,u];
    sgn = DominantSign[c,v+delta+#]& /@ sat;
    ndx = Select[Range[Length[sat]],sgn[[#]] != 0&];
    sat = sat[[ndx]];
    sgn = sgn[[ndx]];
    dr  = DominantRepresentative[c,v+delta+#]-delta& /@ sat;
    mul = MapThread[Times,{sgn,WeightMultiplicity[c,u,#]& /@ sat}];
    wts = Union[dr];
    mul = Map[Apply[Plus,mul[[#]]]&,Map[Flatten[Position[dr,#]]&,wts]];
    Transpose[{mul,wts}]
    ]

Degrees[c_?MatrixQ] := Flatten[ irrDegrees /@ CartanType[c] ]

irrDegrees[{t_,n_}] := 
  Switch[ t,
    "A", Table[i,{i,2,n+1}],
    "B"|"C", Table[2i, {i,n}],
    "D", Append[Table[2i,{i,n-1}],n],
    "E",
      Switch[ n,
        6, {2,5,6,8,9,12},
        7, {2,6,8,10,12,14,18},
        8, {2,8,12,14,18,20,24,30}
        ],
    "F", {2,6,8,12},
    "G", {2,6},
     _, Message[Degrees::unknown,t]; Return[$Failed]
     ]

Exponents[c_?MatrixQ] := Degrees[c]-1

WeylOrder[{}] := 1
WeylOrder[c_?MatrixQ] := Times @@ Degrees[c]

CoxeterNumber[c_?MatrixQ] := LCM @@ Max /@ irrDegrees /@ CartanType[c]

NumberOfReflections[c_?MatrixQ] := Plus @@ Exponents[c]

End[]

Protect[CartanMatrix,CartanType,CoxeterForm,CoxeterNumber,Degrees,DominantQ,
      DominantSign,DominantRepresentative,DominantWeights,Exponents,
      FundamentalWeights,MatrixBlocks,NumberOfReflections,Orbit,OrbitLength,
      PositiveRoots,Reflection,Saturation,SimpleReflections,TensorProduct
      WeightMultiplicity,WeylDimension,WeylOrder]

EndPackage[ ]

