\documentclass{article}
\usepackage{open-axiom}
\begin{document}
\title{\$SPAD/src/algebra sgcf.spad}
\author{Johannes Grabmeier, Thorsten Werther}
\maketitle
\begin{abstract}
\end{abstract}
\eject
\tableofcontents
\eject
\section{package SGCF SymmetricGroupCombinatoricFunctions}
<<package SGCF SymmetricGroupCombinatoricFunctions>>=
)abbrev package SGCF SymmetricGroupCombinatoricFunctions
++ Authors: Johannes Grabmeier, Thorsten Werther
++ Date Created: 03 September 1988
++ Date Last Updated: 07 June 1990
++ Basic Operations: nextPartition, numberOfImproperPartitions,
++   listYoungTableaus, subSet, unrankImproperPartitions0
++ Related Constructors: IntegerCombinatoricFunctions
++ Also See: RepresentationTheoryPackage1, RepresentationTheoryPackage2,
++   IrrRepSymNatPackage
++ AMS Classifications:
++ Keywords: improper partition, partition, subset, Coleman
++ References:
++   G. James/ A. Kerber: The Representation Theory of the Symmetric
++    Group. Encycl. of Math. and its Appl., Vol. 16., Cambridge
++    Univ. Press 1981, ISBN 0-521-30236-6.
++   S.G. Williamson: Combinatorics for Computer Science,
++    Computer Science Press, Rockville, Maryland, USA, ISBN 0-88175-020-4.
++   A. Nijenhuis / H.S. Wilf: Combinatoral Algorithms, Academic Press 1978.
++    ISBN 0-12-519260-6.
++   H. Gollan, J. Grabmeier: Algorithms in Representation Theory and
++    their Realization in the Computer Algebra System Scratchpad,
++    Bayreuther Mathematische Schriften, Heft 33, 1990, 1-23.
++ Description:
++   SymmetricGroupCombinatoricFunctions contains combinatoric
++   functions concerning symmetric groups and representation
++   theory: list young tableaus, improper partitions, subsets
++   bijection of Coleman.
 
SymmetricGroupCombinatoricFunctions(): public == private where
 
  NNI  ==> NonNegativeInteger
  I    ==> Integer
  L    ==> List
  M    ==> Matrix
  V    ==> Vector
  B    ==> Boolean
  ICF  ==> IntegerCombinatoricFunctions Integer
  macro PI == PositiveInteger
 
  public ==> with
 
--    IS THERE A WORKING DOMAIN Tableau ??
--    coerce : M I -> Tableau(I)
--      ++ coerce(ytab) coerces the Young-Tableau ytab to an element of
--      ++ the domain Tableau(I).
 
    coleman : (L I, L I, L I) -> M I
      ++ coleman(alpha,beta,pi):
      ++ there is a bijection from the set of matrices having nonnegative
      ++ entries and row sums {\em alpha}, column sums {\em beta}
      ++ to the set of {\em Salpha - Sbeta} double cosets of the
      ++ symmetric group {\em Sn}. ({\em Salpha} is the Young subgroup
      ++ corresponding to the improper partition {\em alpha}).
      ++ For a representing element {\em pi} of such a double coset,
      ++ coleman(alpha,beta,pi) generates the Coleman-matrix
      ++ corresponding to {\em alpha, beta, pi}.
      ++ Note: The permutation {\em pi} of {\em {1,2,...,n}} has to be given
      ++ in list form.
      ++ Note: the inverse of this map is {\em inverseColeman}
      ++ (if {\em pi} is the lexicographical smallest permutation
      ++ in the coset). For details see James/Kerber.
    inverseColeman : (L I, L I, M I) -> L I
      ++ inverseColeman(alpha,beta,C):
      ++ there is a bijection from the set of matrices having nonnegative
      ++ entries and row sums {\em alpha}, column sums {\em beta}
      ++ to the set of {\em Salpha - Sbeta} double cosets of the
      ++ symmetric group {\em Sn}. ({\em Salpha} is the Young subgroup
      ++ corresponding to the improper partition {\em alpha}).
      ++ For such a matrix C, inverseColeman(alpha,beta,C)
      ++ calculates the lexicographical smallest {\em pi} in the
      ++ corresponding double coset.
      ++ Note: the resulting permutation {\em pi} of {\em {1,2,...,n}} 
      ++ is given in list form.
      ++ Notes: the inverse of this map is {\em coleman}.
      ++ For details, see James/Kerber.
    listYoungTableaus : L PI -> L M I
      ++ listYoungTableaus(lambda) where {\em lambda} is a proper partition
      ++ generates the list of all standard tableaus of shape {\em lambda}
      ++ by means of lattice permutations. The numbers of the lattice
      ++ permutation are interpreted as column labels. Hence the
      ++ contents of these lattice permutations are the conjugate of
      ++ {\em lambda}.
      ++ Notes: the functions {\em nextLatticePermutation} and
      ++ {\em makeYoungTableau} are used.
      ++ The entries are from {\em 0,...,n-1}.
    makeYoungTableau : (L PI,L I) -> M I
      ++ makeYoungTableau(lambda,gitter) computes for a given lattice
      ++ permutation {\em gitter} and for an improper partition {\em lambda}
      ++ the corresponding standard tableau of shape {\em lambda}.
      ++ Notes: see {\em listYoungTableaus}.
      ++ The entries are from {\em 0,...,n-1}.
    nextColeman : (L I, L I, M I) -> M I
      ++ nextColeman(alpha,beta,C) generates the next Coleman matrix
      ++ of column sums {\em alpha} and row sums {\em beta} according
      ++ to the lexicographical order from bottom-to-top.
      ++ The first Coleman matrix is achieved by {\em C=new(1,1,0)}.
      ++ Also, {\em new(1,1,0)} indicates that C is the last Coleman matrix.
    nextLatticePermutation : (L PI, L I, B) -> L I
      ++ nextLatticePermutation(lambda,lattP,constructNotFirst) generates
      ++ the lattice permutation according to the proper partition
      ++ {\em lambda} succeeding the lattice permutation {\em lattP} in
      ++ lexicographical order as long as {\em constructNotFirst} is true.
      ++ If {\em constructNotFirst} is false, the first lattice permutation
      ++ is returned.
      ++ The result {\em nil} indicates that {\em lattP} has no successor.
    nextPartition : (V I, V I, I) -> V I
      ++ nextPartition(gamma,part,number) generates the partition of
      ++ {\em number} which follows {\em part} according to the right-to-left
      ++ lexicographical order. The partition has the property that
      ++ its components do not exceed the corresponding components of
      ++ {\em gamma}. The first partition is achieved by {\em part=[]}.
      ++ Also, {\em []} indicates that {\em part} is the last partition.
    nextPartition : (L I, V I, I) -> V I
      ++ nextPartition(gamma,part,number) generates the partition of
      ++ {\em number} which follows {\em part} according to the right-to-left
      ++ lexicographical order. The partition has the property that
      ++ its components do not exceed the corresponding components of
      ++ {\em gamma}. the first partition is achieved by {\em part=[]}.
      ++ Also, {\em []} indicates that {\em part} is the last partition.
    numberOfImproperPartitions: (I,I) -> I
      ++ numberOfImproperPartitions(n,m) computes the number of partitions
      ++ of the nonnegative integer n in m nonnegative parts with regarding
      ++ the order (improper partitions).
      ++ Example: {\em numberOfImproperPartitions (3,3)} is 10,
      ++ since {\em [0,0,3], [0,1,2], [0,2,1], [0,3,0], [1,0,2], [1,1,1],
      ++ [1,2,0], [2,0,1], [2,1,0], [3,0,0]} are the possibilities.
      ++ Note: this operation has a recursive implementation.
    subSet : (I,I,I) -> L I
      ++ subSet(n,m,k) calculates the {\em k}-th {\em m}-subset of the set
      ++ {\em 0,1,...,(n-1)} in the lexicographic order considered as
      ++ a decreasing map from {\em 0,...,(m-1)} into {\em 0,...,(n-1)}.
      ++ See S.G. Williamson: Theorem 1.60.
      ++ Error: if not {\em (0 <= m <= n and 0 < = k < (n choose m))}.
    unrankImproperPartitions0 : (I,I,I) -> L I
      ++ unrankImproperPartitions0(n,m,k) computes the {\em k}-th improper
      ++ partition of nonnegative n in m nonnegative parts in reverse
      ++ lexicographical order.
      ++ Example: {\em [0,0,3] < [0,1,2] < [0,2,1] < [0,3,0] <
      ++ [1,0,2] < [1,1,1] < [1,2,0] < [2,0,1] < [2,1,0] < [3,0,0]}.
      ++ Error: if k is negative or too big.
      ++ Note: counting of subtrees is done by 
      ++ \spadfunFrom{numberOfImproperPartitions}{SymmetricGroupCombinatoricFunctions}.

    unrankImproperPartitions1: (I,I,I) -> L I
      ++ unrankImproperPartitions1(n,m,k) computes the {\em k}-th improper
      ++ partition of nonnegative n in at most m nonnegative parts 
      ++ ordered as follows: first, in reverse
      ++ lexicographically according to their non-zero parts, then
      ++ according to their positions (i.e. lexicographical order
      ++ using {\em subSet}: {\em [3,0,0] < [0,3,0] < [0,0,3] < [2,1,0] <
      ++ [2,0,1] < [0,2,1] < [1,2,0] < [1,0,2] < [0,1,2] < [1,1,1]}).
      ++ Note: counting of subtrees is done by
      ++ {\em numberOfImproperPartitionsInternal}.
 
  private == add
 
    import Set I
 
    -- declaration of local functions
 
 
    numberOfImproperPartitionsInternal: (I,I,I) -> I
      -- this is used as subtree counting function in
      -- "unrankImproperPartitions1". For (n,m,cm) it counts
      -- the following set of m-tuples: The  first (from left
      -- to right) m-cm non-zero entries are equal, the remaining
      -- positions sum up to n. Example: (3,3,2) counts
      -- [x,3,0], [x,0,3], [0,x,3], [x,2,1], [x,1,2], x non-zero.
 
 
    -- definition of local functions
 
 
    numberOfImproperPartitionsInternal(n,m,cm) ==
      n = 0 => binomial(m,cm)$ICF
      cm = 0 and positive? n => 0
      s := 0
      for i in 0..n-1 repeat
        s := s + numberOfImproperPartitionsInternal(i,m,cm-1)
      s
 
 
    -- definition of exported functions
 
    numberOfImproperPartitions(n,m) ==
      if negative? n or m < 1 then return 0
      if m = 1 or n = 0 then return 1
      s := 0
      for i in 0..n repeat
        s := s + numberOfImproperPartitions(n-i,m-1)
      s
 
 
    unrankImproperPartitions0(n,m,k) ==
      l : L I  := nil$(L I)
      negative? k => error"counting of partitions is started at 0"
      k >= numberOfImproperPartitions(n,m) =>
        error"there are not so many partitions"
      for t in 0..(m-2) repeat
        s : I := 0
        sOld: I
        y : I
        for y: free in 0..n repeat
          sOld := s
          s := s + numberOfImproperPartitions(n-y,m-t-1)
          if s > k then leave
        l := append(l,list(y)$(L I))$(L I)
        k := k - sOld
        n := n - y
      l := append(l,list(n)$(L I))$(L I)
      l
 
 
    unrankImproperPartitions1(n,m,k) ==
      -- we use the counting procedure of the leaves in a tree
      -- having the following structure: First of all non-zero
      -- labels for the sons. If addition along a path gives n,
      -- then we go on creating the subtree for (n choose cm)
      -- where cm is the length of the path. These subsets determine
      -- the positions for the non-zero labels for the partition
      -- to be formeded. The remaining positions are filled by zeros.
      nonZeros   : L I := nil$(L I)
      partition  : V I :=  new(m::NNI,0$I)$(V I)
      negative? k => nonZeros
      k >= numberOfImproperPartitions(n,m) => nonZeros
      cm : I := m    --cm gives the depth of the tree
      while n ~= 0 repeat
        s : I := 0
        cm := cm - 1
        sOld : I
        y : I
        for y: free in n..1 by -1 repeat   --determination of the next son
          sOld := s  -- remember old s
          -- this functions counts the number of elements in a subtree
          s := s + numberOfImproperPartitionsInternal(n-y,m,cm)
          if s > k then leave
        -- y is the next son, so put it into the pathlist "nonZero"
        nonZeros := append(nonZeros,list(y)$(L I))$(L I)
        k := k - sOld    --updating
        n := n - y       --updating
      --having found all m-cm non-zero entries we change the structure
      --of the tree and determine the non-zero positions
      nonZeroPos : L I := reverse subSet(m,m-cm,k)
      --building the partition
      for i in 1..m-cm  repeat partition.(1+nonZeroPos.i) := nonZeros.i
      entries partition
 
 
    subSet(n,m,k) ==
      negative? k or negative? n or negative? m or m > n =>
        error "improper argument to subSet"
      bin : I := binomial$ICF (n,m)
      k >= bin =>
        error "there are not so many subsets"
      l : L I  := []
      n = 0 => l
      mm : I := k
      s  : I := m
      for t in 0..(m-1) repeat
         y : Integer
         for y: free in (s-1)..(n+1) repeat
            if binomial$ICF (y,s) > mm then leave
         l := append (l,list(y-1)$(L I))
         mm := mm - binomial$ICF (y-1,s)
         s := s-1
      l
 
 
    nextLatticePermutation(lambda, lattP, constructNotFirst) ==
 
      lprime  := conjugate(lambda)$PartitionsAndPermutations
      columns := first(lambda)$L(PI)
      rows    := first(lprime)$L(PI)
      n       : NNI :=(+/lambda)::NNI
 
      not constructNotFirst =>   -- first lattice permutation
        lattP := nil$(L I)
        for i in columns..1 by -1 repeat
          for l in 1..lprime(i) repeat
            lattP := cons(i,lattP)
        lattP
 
      help : V I := new(columns,0) -- entry help(i) stores the number
      -- of occurences of number i on our way from right to left
      rightPosition  : NNI := n
      leftEntry : NNI := lattP(rightPosition)::NNI
      ready  : B  := false
      until (ready or (not constructNotFirst)) repeat
        rightEntry : NNI := leftEntry
        leftEntry := lattP(rightPosition-1)::NNI
        help(rightEntry) := help(rightEntry) + 1
        -- search backward decreasing neighbour elements
        if rightEntry > leftEntry then
          if ((lprime(leftEntry)-help(leftEntry)) >_
            (lprime(rightEntry)-help(rightEntry)+1)) then
            -- the elements may be swapped because the number of occurances
            -- of leftEntry would still be greater than those of rightEntry
            ready := true
            j : NNI := leftEntry + 1
            -- search among the numbers leftEntry+1..rightEntry for the
            -- smallest one which can take the place of leftEntry.
            -- negation of condition above:
            while (help(j)=0) or ((lprime(leftEntry)-lprime(j))
              < (help(leftEntry)-help(j)+2)) repeat j := j + 1
            lattP(rightPosition-1) := j
            help(j) := help(j)-1
            help(leftEntry) := help(leftEntry) + 1
            -- reconstruct the rest of the list in increasing order
            for l in rightPosition..n repeat
              j := 0
              while help(1+j) = 0 repeat j := j + 1
              lattP(l::NNI) := j+1
              help(1+j) := help(1+j) - 1
        -- end of "if rightEntry > leftEntry"
        rightPosition := (rightPosition-1)::NNI
        if rightPosition = 1 then constructNotFirst := false
      -- end of repeat-loop
      not constructNotFirst =>  nil$(L I)
      lattP
 
 
    makeYoungTableau(lambda,gitter) ==
      lprime  := conjugate(lambda)$PartitionsAndPermutations
      columns := first(lambda)$L(PI)
      rows    := first(lprime)$L(PI)
      ytab    : M I  := new(rows,columns,0)
      help    : V I  := new(columns,1)
      i : I := -1     -- this makes the entries ranging from 0,..,n-1
                      -- i := 0 would make it from 1,..,n.
      j : I := 0
      for l in 1..maxIndex gitter repeat
        j := gitter(l)
        i := i + 1
        ytab(help(j),j) := i
        help(j) := help(j) + 1
      ytab
 
 
--    coerce(ytab) ==
--      lli := listOfLists(ytab)$(M I)
--      -- remove the filling zeros in each row. It is assumed that
--      -- that there are no such in row 0.
--      for i in 2..maxIndex lli repeat
--        THIS IS DEFINIVELY WRONG, I NEED A FUNCTION WHICH DELETES THE
--        0s, in my version there are no mapping facilities yet.
--        deleteInPlace(not zero?,lli i)
--      tableau(lli)$Tableau(I)
 
 
    listYoungTableaus(lambda) ==
      ytab      : M I
      younglist : L M I := nil$(L M I)
      lattice   := nextLatticePermutation(lambda,nil$L(I),false)
      until null lattice repeat
        ytab      := makeYoungTableau(lambda,lattice)
        younglist := append(younglist,[ytab]$(L M I))$(L M I)
        lattice   := nextLatticePermutation(lambda,lattice,true)
      younglist
 
 
    nextColeman(alpha,beta,C) ==
      nrow  : NNI := #beta
      ncol  : NNI := #alpha
      vnull : V I  := vector(nil()$(L I)) -- empty vector
      vzero : V I  := new(ncol,0)
      vrest : V I  := new(ncol,0)
      cnull : M I  := new(1,1,0)
      coleman := copy C
      if coleman ~= cnull then
        -- look for the first row of "coleman" that has a succeeding
        -- partition, this can be atmost row nrow-1
        i : NNI := (nrow-1)::NNI
        vrest := row(coleman,i) + row(coleman,nrow)
        --for k in 1..ncol repeat
        --  vrest(k) := coleman(i,k) + coleman(nrow,k)
        succ := nextPartition(vrest,row(coleman, i),beta(i))
        while (succ = vnull) repeat
          if i = 1 then return cnull -- part is last partition
          i := (i - 1)::NNI
          --for k in 1..ncol repeat
          --  vrest(k) := vrest(k) + coleman(i,k)
          vrest := vrest + row(coleman,i)
          succ := nextPartition(vrest, row(coleman, i), beta(i))
        j : I := i
        coleman := setRow!(coleman, i, succ)
        --for k in 1..ncol repeat
        --  vrest(k) := vrest(k) - coleman(i,k)
        vrest := vrest - row(coleman,i)
      else
        vrest := vector alpha
        -- for k in 1..ncol repeat
        --  vrest(k) := alpha(k)
        coleman := new(nrow,ncol,0)
        j : I := 0
      for i: local in (j+1)::NNI..nrow-1 repeat
        succ := nextPartition(vrest,vnull,beta(i))
        coleman := setRow!(coleman, i, succ)
        vrest := vrest - succ
        --for k in 1..ncol repeat
        --  vrest(k) := vrest(k) - succ(k)
      setRow!(coleman, nrow, vrest)
 
 
    nextPartition(gamma:V I, part:V I, number:I) ==
      nextPartition(entries gamma, part, number)
 
 
    nextPartition(gamma:L I,part:V I,number:I) ==
      n : NNI := #gamma
      vnull : V I := vector(nil()$(L I)) -- empty vector
      if part ~= vnull then
        i : NNI := 2
        sum := part(1)
        while (part(i) = gamma(i)) or (sum = 0) repeat
          sum := sum + part(i)
          i := i + 1
          if i = 1+n then return vnull -- part is last partition
        sum := sum - 1
        part(i) := part(i) + 1
      else
        sum := number
        part := new(n,0)
        i := 1+n
      j : NNI := 1
      while sum > gamma(j) repeat
        part(j) := gamma(j)
        sum := sum - gamma(j)
        j := j + 1
      part(j) := sum
      for k in j+1..i-1 repeat
        part(k) := 0
      part
 
 
    inverseColeman(alpha,beta,C) ==
      pi   : L I  := nil$(L I)
      nrow : NNI := #beta
      ncol : NNI := #alpha
      help : V I  := new(nrow,0)
      sum  : I   := 1
      for i in 1..nrow repeat
        help(i) := sum
        sum := sum + beta(i)
      for j in 1..ncol repeat
        for i in 1..nrow repeat
          for k in 2..1+C(i,j) repeat
            pi := append(pi,list(help(i))$(L I))
            help(i) := help(i) + 1
      pi
 
 
    coleman(alpha,beta,pi) ==
      nrow : NNI := #beta
      ncol : NNI := #alpha
      temp : L L I := nil$(L L I)
      help : L I  := nil$(L I)
      colematrix : M I := new(nrow,ncol,0)
      betasum  : NNI := 0
      alphasum : NNI := 0
      for i in 1..ncol repeat
        help := nil$(L I)
        for j in alpha(i)..1 by-1 repeat
          help := cons(pi(j::NNI+alphasum),help)
        alphasum := (alphasum + alpha(i))::NNI
        temp := append(temp,list(help)$(L L I))
      for i in 1..nrow repeat
        help := nil$(L I)
        for j in beta(i)..1 by-1 repeat
          help := cons(j::NNI+betasum, help)
        betasum := (betasum + beta(i))::NNI
        for j in 1..ncol repeat
          colematrix(i,j) := #intersect(brace(help),brace(temp(j)))
      colematrix

@
\section{License}
<<license>>=
--Copyright (c) 1991-2002, The Numerical ALgorithms Group Ltd.
--All rights reserved.
--
--Redistribution and use in source and binary forms, with or without
--modification, are permitted provided that the following conditions are
--met:
--
--    - Redistributions of source code must retain the above copyright
--      notice, this list of conditions and the following disclaimer.
--
--    - Redistributions in binary form must reproduce the above copyright
--      notice, this list of conditions and the following disclaimer in
--      the documentation and/or other materials provided with the
--      distribution.
--
--    - Neither the name of The Numerical ALgorithms Group Ltd. nor the
--      names of its contributors may be used to endorse or promote products
--      derived from this software without specific prior written permission.
--
--THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
--IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
--TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
--PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
--OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
--EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
--PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
--PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
--LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
--NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
--SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@
<<*>>=
<<license>>

<<package SGCF SymmetricGroupCombinatoricFunctions>>
@
\eject
\begin{thebibliography}{99}
\bibitem{1} nothing
\end{thebibliography}
\end{document}