{-# LANGUAGE CPP, BangPatterns, PatternGuards #-}
module Math.Combinat.Groups.Free where
#ifdef MIN_VERSION_base
#if MIN_VERSION_base(4,7,1)
import Prelude hiding ( Word )
#endif
#elif __GLASGOW_HASKELL__ >= 709
import Prelude hiding ( Word )
#endif
import Data.Char ( chr )
import Data.List ( mapAccumL , groupBy )
import Control.Monad ( liftM )
import System.Random
import Math.Combinat.Numbers
import Math.Combinat.Sign
import Math.Combinat.Helper
data Generator idx
= Gen !idx
| Inv !idx
deriving (Eq,Ord,Show,Read)
genIdx :: Generator idx -> idx
genIdx g = case g of
Gen x -> x
Inv x -> x
genSign :: Generator idx -> Sign
genSign g = case g of { Gen _ -> Plus ; Inv _ -> Minus }
genSignValue :: Generator idx -> Int
genSignValue g = case g of { Gen _ -> (1::Int) ; Inv _ -> (-1::Int) }
absGen :: Generator idx -> Generator idx
absGen g = case g of
Gen x -> Gen x
Inv x -> Gen x
type Word idx = [Generator idx]
showGen :: Generator Int -> Char
showGen (Gen i) = chr (96+i)
showGen (Inv i) = chr (64+i)
showWord :: Word Int -> String
showWord = map showGen
instance Functor Generator where
fmap f g = case g of
Gen x -> Gen (f x)
Inv y -> Inv (f y)
inverseGen :: Generator a -> Generator a
inverseGen g = case g of
Gen x -> Inv x
Inv x -> Gen x
inverseWord :: Word a -> Word a
inverseWord = map inverseGen . reverse
allWords
:: Int
-> Int
-> [Word Int]
allWords g = go where
go !0 = [[]]
go !n = [ x:xs | xs <- go (n-1) , x <- elems ]
elems = [ Gen a | a<-[1..g] ]
++ [ Inv a | a<-[1..g] ]
allWordsNoInv
:: Int
-> Int
-> [Word Int]
allWordsNoInv g = go where
go !0 = [[]]
go !n = [ x:xs | xs <- go (n-1) , x <- elems ]
elems = [ Gen a | a<-[1..g] ]
randomGenerator
:: RandomGen g
=> Int
-> g -> (Generator Int, g)
randomGenerator !d !g0 = (gen, g2) where
(b, !g1) = random g0
(k, !g2) = randomR (1,d) g1
gen = if b then Gen k else Inv k
randomGeneratorNoInv
:: RandomGen g
=> Int
-> g -> (Generator Int, g)
randomGeneratorNoInv !d !g0 = (Gen k, g1) where
(!k, !g1) = randomR (1,d) g0
randomWord
:: RandomGen g
=> Int
-> Int
-> g -> (Word Int, g)
randomWord !d !n !g0 = (word,g1) where
(g1,word) = mapAccumL (\g _ -> swap (randomGenerator d g)) g0 [1..n]
randomWordNoInv
:: RandomGen g
=> Int
-> Int
-> g -> (Word Int, g)
randomWordNoInv !d !n !g0 = (word,g1) where
(g1,word) = mapAccumL (\g _ -> swap (randomGeneratorNoInv d g)) g0 [1..n]
{-# SPECIALIZE multiplyFree :: Word Int -> Word Int -> Word Int #-}
{-# SPECIALIZE equivalentFree :: Word Int -> Word Int -> Bool #-}
{-# SPECIALIZE reduceWordFree :: Word Int -> Word Int #-}
{-# SPECIALIZE reduceWordFreeNaive :: Word Int -> Word Int #-}
multiplyFree :: Eq idx => Word idx -> Word idx -> Word idx
multiplyFree w1 w2 = reduceWordFree (w1 ++ w2)
equivalentFree :: Eq idx => Word idx -> Word idx -> Bool
equivalentFree w1 w2 = null $ reduceWordFree $ w1 ++ inverseWord w2
reduceWordFree :: Eq idx => Word idx -> Word idx
reduceWordFree = loop where
loop w = case reduceStep w of
Nothing -> w
Just w' -> loop w'
reduceStep :: Eq a => Word a -> Maybe (Word a)
reduceStep = go False where
go !changed w = case w of
(Gen x : Inv y : rest) | x==y -> go True rest
(Inv x : Gen y : rest) | x==y -> go True rest
(this : rest) -> liftM (this:) $ go changed rest
_ -> if changed then Just w else Nothing
reduceWordFreeNaive :: Eq idx => Word idx -> Word idx
reduceWordFreeNaive = loop where
loop w = let w' = step w in if w/=w' then loop w' else w
step = concatMap worker . groupBy (equating genIdx) where
worker gs
| s>0 = replicate s (Gen i)
| s<0 = replicate (abs s) (Inv i)
| otherwise = []
where
i = genIdx (head gs)
s = sum' (map genSignValue gs)
countIdentityWordsFree
:: Int
-> Int
-> Integer
countIdentityWordsFree g n = countWordReductionsFree g n 0
countWordReductionsFree
:: Int
-> Int
-> Int
-> Integer
countWordReductionsFree gens_ nn_ kk_
| nn==0 = if k==0 then 1 else 0
| even nn && kk == 0 = sum [ ( binomial (nn-i) (n -i) * gg^(i ) * (gg-1)^(n -i ) * ( i) ) `div` (nn-i) | i<-[0..n ] ]
| even nn && even kk = sum [ ( binomial (nn-i) (n-k-i) * gg^(i+1) * (gg-1)^(n+k-i-1) * (kk+i) ) `div` (nn-i) | i<-[0..n-k] ]
| odd nn && odd kk = sum [ ( binomial (nn-i) (n-k-i) * gg^(i+1) * (gg-1)^(n+k-i ) * (kk+i) ) `div` (nn-i) | i<-[0..n-k] ]
| otherwise = 0
where
g = fromIntegral gens_ :: Integer
nn = fromIntegral nn_ :: Integer
kk = fromIntegral kk_ :: Integer
gg = 2*g
n = div nn 2
k = div kk 2
{-# SPECIALIZE multiplyZ2 :: Word Int -> Word Int -> Word Int #-}
{-# SPECIALIZE multiplyZ3 :: Word Int -> Word Int -> Word Int #-}
{-# SPECIALIZE multiplyZm :: Int -> Word Int -> Word Int -> Word Int #-}
multiplyZ2 :: Eq idx => Word idx -> Word idx -> Word idx
multiplyZ2 w1 w2 = reduceWordZ2 (w1 ++ w2)
multiplyZ3 :: Eq idx => Word idx -> Word idx -> Word idx
multiplyZ3 w1 w2 = reduceWordZ3 (w1 ++ w2)
multiplyZm :: Eq idx => Int -> Word idx -> Word idx -> Word idx
multiplyZm k w1 w2 = reduceWordZm k (w1 ++ w2)
{-# SPECIALIZE equivalentZ2 :: Word Int -> Word Int -> Bool #-}
{-# SPECIALIZE equivalentZ3 :: Word Int -> Word Int -> Bool #-}
{-# SPECIALIZE equivalentZm :: Int -> Word Int -> Word Int -> Bool #-}
equivalentZ2 :: Eq idx => Word idx -> Word idx -> Bool
equivalentZ2 w1 w2 = null $ reduceWordZ2 $ w1 ++ inverseWord w2
equivalentZ3 :: Eq idx => Word idx -> Word idx -> Bool
equivalentZ3 w1 w2 = null $ reduceWordZ3 $ w1 ++ inverseWord w2
equivalentZm :: Eq idx => Int -> Word idx -> Word idx -> Bool
equivalentZm m w1 w2 = null $ reduceWordZm m $ w1 ++ inverseWord w2
{-# SPECIALIZE reduceWordZ2 :: Word Int -> Word Int #-}
{-# SPECIALIZE reduceWordZ3 :: Word Int -> Word Int #-}
{-# SPECIALIZE reduceWordZm :: Int -> Word Int -> Word Int #-}
reduceWordZ2 :: Eq idx => Word idx -> Word idx
reduceWordZ2 = loop where
loop w = case reduceStep w of
Nothing -> w
Just w' -> loop w'
reduceStep :: Eq a => Word a -> Maybe (Word a)
reduceStep = go False where
go !changed w = case w of
(Gen x : Gen y : rest) | x==y -> go True rest
(Gen x : Inv y : rest) | x==y -> go True rest
(Inv x : Gen y : rest) | x==y -> go True rest
(Inv x : Inv y : rest) | x==y -> go True rest
(this : rest) -> liftM (absGen this:) $ go changed rest
_ -> if changed then Just w else Nothing
reduceWordZ3 :: Eq idx => Word idx -> Word idx
reduceWordZ3 = loop where
loop w = case reduceStep w of
Nothing -> w
Just w' -> loop w'
reduceStep :: Eq a => Word a -> Maybe (Word a)
reduceStep = go False where
go !changed w = case w of
(Gen x : Inv y : rest) | x==y -> go True rest
(Inv x : Gen y : rest) | x==y -> go True rest
(Gen x : Gen y : Gen z : rest) | x==y && y==z -> go True rest
(Inv x : Inv y : Inv z : rest) | x==y && y==z -> go True rest
(Gen x : Gen y : rest) | x==y -> go True (Inv x : rest)
(Inv x : Inv y : rest) | x==y -> go True (Gen x : rest)
(this : rest) -> liftM (this:) $ go changed rest
_ -> if changed then Just w else Nothing
reduceWordZm :: Eq idx => Int -> Word idx -> Word idx
reduceWordZm m = loop where
loop w = case reduceStep w of
Nothing -> w
Just w' -> loop w'
halfm = div m 2
reduceStep = go False where
go !changed w = case w of
(Gen x : Inv y : rest) | x==y -> go True rest
(Inv x : Gen y : rest) | x==y -> go True rest
something | Just (k,rest) <- dropIfMoreThanHalf w -> go True (replicate (m-k) (inverseGen (head w)) ++ rest)
(this : rest) -> liftM (this:) $ go changed rest
_ -> if changed then Just w else Nothing
dropIfMoreThanHalf w =
let (!k,rest) = dropWhileEqual w
in if k > halfm then Just (k,rest)
else Nothing
dropWhileEqual [] = (0,[])
dropWhileEqual (x0:rest) = go 1 rest where
go !k [] = (k,[])
go !k xxs@(x:xs) = if k==m then (m,xxs)
else if x==x0 then go (k+1) xs
else (k,xxs)
{-# SPECIALIZE reduceWordZ2Naive :: Word Int -> Word Int #-}
{-# SPECIALIZE reduceWordZ3Naive :: Word Int -> Word Int #-}
{-# SPECIALIZE reduceWordZmNaive :: Int -> Word Int -> Word Int #-}
reduceWordZ2Naive :: Eq idx => Word idx -> Word idx
reduceWordZ2Naive = loop where
loop w = let w' = step w in if w/=w' then loop w' else w
step = concatMap worker . groupBy (equating genIdx) where
worker gs =
case mod s 2 of
1 -> [Gen i]
0 -> []
_ -> error "reduceWordZ2: fatal error, shouldn't happen"
where
i = genIdx (head gs)
s = sum' (map genSignValue gs)
reduceWordZ3Naive :: Eq idx => Word idx -> Word idx
reduceWordZ3Naive = loop where
loop w = let w' = step w in if w/=w' then loop w' else w
step = concatMap worker . groupBy (equating genIdx) where
worker gs =
case mod s 3 of
0 -> []
1 -> [Gen i]
2 -> [Inv i]
_ -> error "reduceWordZ3: fatal error, shouldn't happen"
where
i = genIdx (head gs)
s = sum' (map genSignValue gs)
reduceWordZmNaive :: Eq idx => Int -> Word idx -> Word idx
reduceWordZmNaive m = loop where
loop w = let w' = step w in if w/=w' then loop w' else w
step = concatMap worker . groupBy (equating genIdx) where
halfm1 = div (m+1) 2
worker gs
| mods <= halfm1 = replicate mods (Gen i)
| otherwise = replicate (m-mods) (Inv i)
where
i = genIdx (head gs)
s = sum' (map genSignValue gs)
mods = mod s m
countIdentityWordsZ2
:: Int
-> Int
-> Integer
countIdentityWordsZ2 g n = countWordReductionsZ2 g n 0
countWordReductionsZ2
:: Int
-> Int
-> Int
-> Integer
countWordReductionsZ2 gens_ nn_ kk_
| nn==0 = if k==0 then 1 else 0
| even nn && kk == 0 = sum [ ( binomial (nn-i) (n -i) * g^(i ) * (g-1)^(n -i ) * ( i) ) `div` (nn-i) | i<-[0..n ] ]
| even nn && even kk = sum [ ( binomial (nn-i) (n-k-i) * g^(i+1) * (g-1)^(n+k-i-1) * (kk+i) ) `div` (nn-i) | i<-[0..n-k] ]
| odd nn && odd kk = sum [ ( binomial (nn-i) (n-k-i) * g^(i+1) * (g-1)^(n+k-i ) * (kk+i) ) `div` (nn-i) | i<-[0..n-k] ]
| otherwise = 0
where
g = fromIntegral gens_ :: Integer
nn = fromIntegral nn_ :: Integer
kk = fromIntegral kk_ :: Integer
n = div nn 2
k = div kk 2
countIdentityWordsZ3NoInv
:: Int
-> Int
-> Integer
countIdentityWordsZ3NoInv gens_ nn_
| nn==0 = 1
| mod nn 3 == 0 = sum [ ( binomial (3*n-i-1) (n-i) * g^i * (g-1)^(n-i) * i ) `div` n | i<-[1..n] ]
| otherwise = 0
where
g = fromIntegral gens_ :: Integer
nn = fromIntegral nn_ :: Integer
n = div nn 3