{-# LANGUAGE CPP, BangPatterns #-}
module Math.Combinat.Partitions.Skew where
import Data.List
import Math.Combinat.Classes
import Math.Combinat.Partitions.Integer
import Math.Combinat.ASCII
newtype SkewPartition = SkewPartition [(Int,Int)] deriving (Eq,Ord,Show)
mkSkewPartition :: (Partition,Partition) -> SkewPartition
mkSkewPartition ( lam@(Partition bs) , mu@(Partition as)) = if mu `isSubPartitionOf` lam
then SkewPartition $ zipWith (\b a -> (a,b-a)) bs (as ++ repeat 0)
else error "mkSkewPartition: mu should be a subpartition of lambda!"
safeSkewPartition :: (Partition,Partition) -> Maybe SkewPartition
safeSkewPartition ( lam@(Partition bs) , mu@(Partition as)) = if mu `isSubPartitionOf` lam
then Just $ SkewPartition $ zipWith (\b a -> (a,b-a)) bs (as ++ repeat 0)
else Nothing
skewPartitionWeight :: SkewPartition -> Int
skewPartitionWeight (SkewPartition abs) = foldl' (+) 0 (map snd abs)
instance HasWeight SkewPartition where
weight = skewPartitionWeight
normalizeSkewPartition :: SkewPartition -> SkewPartition
normalizeSkewPartition (SkewPartition abs) = SkewPartition abs' where
(as,bs) = unzip abs
a0 = minimum as
k = length (takeWhile (==0) bs)
abs' = zip [ a-a0 | a <- drop k as ] (drop k bs)
fromSkewPartition :: SkewPartition -> (Partition,Partition)
fromSkewPartition (SkewPartition list) = (toPartition (zipWith (+) as bs) , toPartition (filter (>0) as)) where
(as,bs) = unzip list
outerPartition :: SkewPartition -> Partition
outerPartition = fst . fromSkewPartition
innerPartition :: SkewPartition -> Partition
innerPartition = snd . fromSkewPartition
dualSkewPartition :: SkewPartition -> SkewPartition
dualSkewPartition = mkSkewPartition . f . fromSkewPartition where
f (lam,mu) = (dualPartition lam, dualPartition mu)
instance HasDuality SkewPartition where
dual = dualSkewPartition
skewPartitionElements :: SkewPartition -> [(Int, Int)]
skewPartitionElements (SkewPartition abs) = concat
[ [ (i,j) | j <- [a+1 .. a+b] ]
| (i,(a,b)) <- zip [1..] abs
]
skewPartitionsWithOuterShape :: Partition -> Int -> [SkewPartition]
skewPartitionsWithOuterShape outer skewWeight
| innerWeight < 0 || innerWeight > outerWeight = []
| otherwise = [ mkSkewPartition (outer,inner) | inner <- subPartitions innerWeight outer ]
where
outerWeight = weight outer
innerWeight = outerWeight - skewWeight
allSkewPartitionsWithOuterShape :: Partition -> [SkewPartition]
allSkewPartitionsWithOuterShape outer
= concat [ skewPartitionsWithOuterShape outer w | w<-[0..outerWeight] ]
where
outerWeight = weight outer
skewPartitionsWithInnerShape :: Partition -> Int -> [SkewPartition]
skewPartitionsWithInnerShape inner skewWeight
| innerWeight > outerWeight = []
| otherwise = [ mkSkewPartition (outer,inner) | outer <- superPartitions outerWeight inner ]
where
outerWeight = innerWeight + skewWeight
innerWeight = weight inner
asciiSkewFerrersDiagram :: SkewPartition -> ASCII
asciiSkewFerrersDiagram = asciiSkewFerrersDiagram' ('@','.') EnglishNotation
asciiSkewFerrersDiagram'
:: (Char,Char)
-> PartitionConvention
-> SkewPartition
-> ASCII
asciiSkewFerrersDiagram' (outer,inner) orient (SkewPartition abs) = asciiFromLines stuff where
stuff = case orient of
EnglishNotation -> ls
EnglishNotationCCW -> reverse (transpose ls)
FrenchNotation -> reverse ls
ls = [ replicate a inner ++ replicate b outer | (a,b) <- abs ]
instance DrawASCII SkewPartition where
ascii = asciiSkewFerrersDiagram