{-# LANGUAGE
CPP, BangPatterns,
ScopedTypeVariables, ExistentialQuantification,
DataKinds, KindSignatures, Rank2Types #-}
module Math.Combinat.Groups.Braid.NF
(
BraidNF (..)
, nfReprWord
, braidNormalForm
, braidNormalForm'
, braidNormalFormNaive'
, permWordStartingSet
, permWordFinishingSet
, permutationStartingSet
, permutationFinishingSet
)
where
import Data.Proxy
import GHC.TypeLits
import Control.Monad
import Data.List ( mapAccumL , foldl' , (\\) )
import Data.Array.Unboxed
import Data.Array.ST
import Data.Array.IArray
import Data.Array.MArray
import Data.Array.Unsafe
import Data.Array.Base
import Control.Monad.ST
import Math.Combinat.Helper
import Math.Combinat.Sign
import Math.Combinat.Permutations ( Permutation(..) , isIdentityPermutation , isReversePermutation )
import qualified Math.Combinat.Permutations as P
import Math.Combinat.Groups.Braid
data BraidNF (n :: Nat) = BraidNF
{ _nfDeltaExp :: !Int
, _nfPerms :: [Permutation]
}
deriving (Eq,Ord,Show)
nfReprWord :: KnownNat n => BraidNF n -> Braid n
nfReprWord (BraidNF k perms) = freeReduceBraidWord $ composeMany (deltas ++ rest) where
deltas
| k > 0 = replicate k halfTwist
| k < 0 = replicate (-k) (inverse halfTwist)
| otherwise = []
rest = map permutationBraid perms
braidNormalForm :: KnownNat n => Braid n -> BraidNF n
braidNormalForm = braidNormalForm' . freeReduceBraidWord
braidNormalForm' :: KnownNat n => Braid n -> BraidNF n
braidNormalForm' braid@(Braid gens) = BraidNF (dexp+pexp) perms where
n = numberOfStrands braid
invless = replaceInverses n gens
(dexp,posxword) = moveDeltasLeft n invless
factors = leftGreedyFactors n $ expandPosXWord n posxword
(pexp,perms) = normalizePermFactors n $ map (_braidPermutation n) factors
braidNormalFormNaive' :: KnownNat n => Braid n -> BraidNF n
braidNormalFormNaive' braid@(Braid gens) = BraidNF (dexp+pexp) perms where
n = numberOfStrands braid
invless = replaceInversesNaive gens
(dexp,posxword) = moveDeltasLeft n invless
factors = leftGreedyFactors n $ expandPosXWord n posxword
(pexp,perms) = normalizePermFactors n $ map (_braidPermutation n) factors
replaceInverses :: Int -> [BrGen] -> [XGen]
replaceInverses n gens = worker gens where
worker [] = []
worker xs = replaceNegs neg ++ map (XSigma . brGenIdx) pos ++ worker rest where
(neg,tmp ) = span (isMinus . brGenSign) xs
(pos,rest) = span (isPlus . brGenSign) tmp
replaceNegs gs = concatMap replaceFac facs where
facs = leftGreedyFactors n $ map brGenIdx gs
replaceFac idxs = XDelta (-1) : map XSigma (_permutationBraid perm) where
perm = (P.reversePermutation n) `P.multiply` (P.adjacentTranspositions n idxs)
replaceInversesNaive :: [BrGen] -> [XGen]
replaceInversesNaive gens = concatMap f gens where
f (Sigma i) = [ XSigma i ]
f (SigmaInv i) = [ XDelta (-1) , XL i ]
data XGen
= XDelta !Int
| XSigma !Int
| XL !Int
| XTauL !Int
deriving (Eq,Show)
isXDelta :: XGen -> Bool
isXDelta x = case x of { XDelta {} -> True ; _ -> False }
moveDeltasLeft :: Int -> [XGen] -> (Int,[XGen])
moveDeltasLeft n input = (finalExp, finalPosWord) where
(XDelta finalExp : finalPosWord) = reverse $ worker 0 (reverse input)
worker dexp [] = [ XDelta dexp ]
worker !dexp xs = this' ++ worker dexp' rest where
(delta,notdelta) = span isXDelta xs
(this ,rest ) = span (not . isXDelta) notdelta
dexp' = dexp + sumDeltas delta
this' = if even dexp'
then this
else map xtau this
sumDeltas :: [XGen] -> Int
sumDeltas xs = foldl' (+) 0 [ k | XDelta k <- xs ]
xtau :: XGen -> XGen
xtau (XSigma j) = XSigma (n-j)
xtau (XDelta k) = XDelta k
xtau (XL k) = XTauL k
xtau (XTauL k) = XL k
expandPosXWord :: Int -> [XGen] -> [Int]
expandPosXWord n = concatMap f where
posHalfTwist = _halfTwist n
jtau :: Int -> Int
jtau j = n-j
posLTable = listArray (1,n-1) [ _permutationBraid (posLPerm n i) | i<-[1..n-1] ] :: Array Int [Int]
posTauLTable = amap (map jtau) posLTable
f x = case x of
XSigma i -> [i]
XL i -> posLTable ! i
XTauL i -> posTauLTable ! i
XDelta i
| i > 0 -> concat (replicate i posHalfTwist)
| i < 0 -> error "expandPosXWord: negative delta power"
| otherwise -> []
expandAnyXWord :: forall n. KnownNat n => [XGen] -> Braid n
expandAnyXWord xgens = braid where
n = numberOfStrands braid
braid = composeMany (map f xgens)
posHalfTwist = halfTwist :: Braid n
negHalfTwist = inverse posHalfTwist :: Braid n
posLTable = listArray (1,n-1) [ permutationBraid (posLPerm n i) | i<-[1..n-1] ] :: Array Int (Braid n)
posTauLTable = amap tau posLTable
f :: XGen -> Braid n
f x = case x of
XSigma i -> sigma i
XL i -> posLTable ! i
XTauL i -> posTauLTable ! i
XDelta i
| i > 0 -> composeMany (replicate i posHalfTwist)
| i < 0 -> composeMany (replicate (-i) negHalfTwist)
| otherwise -> identity
posL :: KnownNat n => Int -> Braid n
posL k = braid where
n = numberOfStrands braid
braid = permutationBraid (posLPerm n k)
posR :: KnownNat n => Int -> Braid n
posR k = braid where
n = numberOfStrands braid
braid = permutationBraid (posRPerm n k)
posLPerm :: Int -> Int -> Permutation
posLPerm n k
| k>0 && k<n = (P.reversePermutation n `P.multiply` P.adjacentTransposition n k)
| otherwise = error "posLPerm: index out of range"
posRPerm :: Int -> Int -> Permutation
posRPerm n k
| k>0 && k<n = (P.adjacentTransposition n k `P.multiply` P.reversePermutation n )
| otherwise = error "posRPerm: index out of range"
filterDeltaFactors :: Int -> [[Int]] -> (Int, [[Int]])
filterDeltaFactors n facs = (exp',facs'') where
(exp',facs') = go 0 (reverse facs)
jtau j = n-j
facs'' = reverse facs'
maxlen = div (n*(n-1)) 2
go !e [] = (e,[])
go !e (xs:xxs)
| null xs = go e xxs
| length xs == maxlen = go (e+1) xxs
| otherwise =
if even e
then let (e',yys) = go e xxs in (e' , xs : yys)
else let (e',yys) = go e xxs in (e' , map jtau xs : yys)
permWordStartingSet :: Int -> [Int] -> [Int]
permWordStartingSet n xs = permWordFinishingSet n (reverse xs)
permWordFinishingSet :: Int -> [Int] -> [Int]
permWordFinishingSet n input = runST action where
action :: forall s. ST s [Int]
action = do
perm <- newArray_ (1,n) :: ST s (STUArray s Int Int)
forM_ [1..n] $ \i -> writeArray perm i i
forM_ input $ \i -> do
a <- readArray perm i
b <- readArray perm (i+1)
writeArray perm i b
writeArray perm (i+1) a
flip filterM [1..n-1] $ \i -> do
a <- readArray perm i
b <- readArray perm (i+1)
return (b<a)
permutationStartingSet :: Permutation -> [Int]
permutationStartingSet = permutationFinishingSet . P.inverse
permutationFinishingSet :: Permutation -> [Int]
permutationFinishingSet (Permutation arr)
= [ i | i<-[1..n-1] , arr ! i > arr ! (i+1) ] where (1,n) = bounds arr
fails_lemmma_2_5 :: Int -> [Permutation]
fails_lemmma_2_5 n = [ p | p <- P.permutations n , not (test p) ] where
test p = and [ check i | i<-[1..n-1] ] where
w = _permutationBraid p
s = permWordStartingSet n w
check i = _isPermutationBraid n (i:w) == (not $ elem i s)
normalizePermFactors :: Int -> [Permutation] -> (Int,[Permutation])
normalizePermFactors n = go 0 where
go !acc input =
if (exp==0 && input == output)
then (acc,input)
else go (acc+exp) output
where
(exp,output) = normalizePermFactors1 n input
normalizePermFactors1 :: Int -> [Permutation] -> (Int,[Permutation])
normalizePermFactors1 n input = (exp, reverse output) where
(exp, output) = worker 0 (reverse input)
worker :: Int -> [Permutation] -> (Int,[Permutation])
worker = worker' 0 0
worker' :: Int -> Int -> Int -> [Permutation] -> (Int,[Permutation])
worker' !ep !eq !e (!p : rest@(!q : rest'))
| isIdentityPermutation p = worker' eq 0 e rest
| isReversePermutation p = worker' eq 0 (e+1) rest
| isIdentityPermutation q = worker' ep 0 e (p : rest')
| isReversePermutation q = worker' (ep-1) 0 (e+1) (p : rest')
| otherwise =
case permutationStartingSet preal \\ permutationFinishingSet qreal of
[] -> let (e',rs) = worker' eq 0 e rest in (e', preal : rs)
(j:_) -> worker' (-e) (-e) e (p':q':rest') where
s = P.adjacentTransposition n j
p' = P.multiply s preal
q' = P.multiply qreal s
where
preal = oddTau (e+ep) p
qreal = oddTau (e+eq) q
worker' _ _ !e [ ] = (e,[])
worker' !ep _ !e [p]
| isIdentityPermutation p = (e , [])
| isReversePermutation p = (e+1 , [])
| otherwise = (e , [oddTau (e+ep) p] )
oddTau :: Int -> Permutation -> Permutation
oddTau !e p = if even e then p else tauPerm p
leftGreedyFactors :: Int -> [Int] -> [[Int]]
leftGreedyFactors n input = filter (not . null) $ runST (action input) where
action :: forall s. [Int] -> ST s [[Int]]
action input = do
perm <- newArray_ (1,n) :: ST s (STUArray s Int Int)
forM_ [1..n] $ \i -> writeArray perm i i
let doSwap :: Int -> ST s ()
doSwap i = do
a <- readArray perm i
b <- readArray perm (i+1)
writeArray perm i b
writeArray perm (i+1) a
mat <- newArray ((1,1),(n,n)) 0 :: ST s (STUArray s (Int,Int) Int)
let clearMat = forM_ [1..n] $ \i ->
forM_ [1..n] $ \j -> writeArray mat (i,j) 0
let doAdd1 :: Int -> Int -> ST s Int
doAdd1 i j = do
x <- readArray mat (i,j)
let y = x+1
writeArray mat (i,j) y
writeArray mat (j,i) y
return y
let worker :: [Int] -> ST s [[Int]]
worker [] = return [[]]
worker (p:ps) = do
u <- readArray perm p
v <- readArray perm (p+1)
c <- doAdd1 u v
doSwap p
if c<=1
then do
(f:fs) <- worker ps
return ((p:f):fs)
else do
clearMat
fs <- worker (p:ps)
return ([]:fs)
worker input