module PermutationGroups where

import Array
import List

-- GROUP

class Group a where
  identity :: Int -> a
  isIdentity :: a -> Bool
  (*>) :: a -> a -> a     -- right multiplication
  inverse :: a -> a

conjugate g h = inverse h *> g *> h

prod gs = foldl1 (*>) gs


-- PERMUTATION

newtype Permutation = PL [Int] deriving (Eq, Ord, Read, Show)

x .^ (PL g) = g !! (x-1)

--instance Show Permutation where
--  show g = show (toCycles' g)
--  show g = "(" ++ (foldl1 (++) (map show g)) ++ ")"

instance Group Permutation where
  identity n = PL [1..n]
  isIdentity (PL xs) = all (\(i,j) -> i==j) (zip [1..] xs)
  (PL g) *> h = PL (map (.^ h) g)
  inverse (PL g) = PL (map snd (sort (zip g [1..])))

fromCycles cs = PL (map snd (sort pointActions))
  where
    pointActions = concat (map fromCycle cs)

fromCycle is = zip is (rotateL is)

fromCycles' n cs = PL (elems (array (1,n) [(i,i) | i <- [1..n]] // (concat (map fromCycle cs))))

findOrbit (PL permutation) elt =
  let buildOrbit os ps e = 
        if (elem e os) 
          then os
          else let ei = elemIndex e ps in 
                 case ei of
                   Nothing -> os
                   Just e' -> buildOrbit ([e] ++ os) ps (e'+1)
  in buildOrbit [] permutation elt

toCycles (PL permutation) =
  let getOrbits out [] per = out
      getOrbits out els per =
        let orbit = findOrbit per (head els)
            els' = els \\ orbit
        in getOrbits (out ++ [orbit]) els' per
  in getOrbits [] permutation (PL permutation)

rotateL (x:xs) = xs ++ [x]

saturateCycles :: [[Int]] -> Int -> [[Int]]
saturateCycles cs n = cs ++ ( group ( [1..n] \\ foldl1 (++) cs ) )

desaturateCycles cs = filter (\x -> length x > 1) cs

-- CGT ALGORITHMS

generateGroup generators = 
  let g0 = head generators
      i = g0 *> inverse g0
      addElts group [] gens = group
      addElts group cands gens = 
        let cand = take 1 cands
            group' = group ++ cand
            newcands = map (*> (head cand)) gens
            cands' = (tail cands) ++ (newcands \\ (group' ++ cands))
        in 
            addElts group' cands' gens
  in addElts [] [i] generators










