{-# OPTIONS -fno-implicit-prelude #-} {- | Copyright : (c) Mikael Johansson 2006 Maintainer : mik@math.uni-jena.de Stability : provisional Portability : requires multi-parameter type classes Permutation of Integers represented by cycles. -} module MathObj.Permutation.CycleList where import Data.Set(Set) import qualified Data.Set as Set import Data.List (unfoldr) import Data.Array(Ix) import qualified Data.Array as Array import NumericPrelude.List (takeMatch) import NumericPrelude.Condition (toMaybe) import NumericPrelude (fromInteger) import PreludeBase type Cycle i = [i] type T i = [Cycle i] fromFunction :: (Ix i) => (i, i) -> (i -> i) -> T i fromFunction rng f = let extractCycle available = do el <- choose available let orb = orbit f el return (orb, Set.difference available (Set.fromList orb)) cycles = unfoldr extractCycle (Set.fromList (Array.range rng)) in keepEssentials cycles -- right action of a cycle cycleRightAction :: (Eq i) => i -> Cycle i -> i x `cycleRightAction` c = cycleAction c x -- left action of a cycle cycleLeftAction :: (Eq i) => Cycle i -> i -> i c `cycleLeftAction` x = cycleAction (reverse c) x cycleAction :: (Eq i) => [i] -> i -> i cycleAction cyc x = case dropWhile (x/=) (cyc ++ [head cyc]) of _:y:_ -> y _ -> x cycleOrbit :: (Ord i) => Cycle i -> i -> [i] cycleOrbit cyc = orbit (flip cycleRightAction cyc) {- | Right (left?) group action on the Integers. Close to, but not the same as the module action in Algebra.Module. -} (*>) :: (Eq i) => T i -> i -> i p *> x = foldr (flip cycleRightAction) x p cyclesOrbit ::(Ord i) => T i -> i -> [i] cyclesOrbit p = orbit (p *>) orbit :: (Ord i) => (i -> i) -> i -> [i] orbit op x0 = takeUntilRepetition (iterate op x0) -- | candidates for NumericPrelude.List ? takeUntilRepetition :: Ord a => [a] -> [a] takeUntilRepetition xs = let accs = scanl (flip Set.insert) Set.empty xs lenlist = takeWhile not (zipWith Set.member xs accs) in takeMatch lenlist xs takeUntilRepetitionSlow :: Eq a => [a] -> [a] takeUntilRepetitionSlow xs = let accs = scanl (flip (:)) [] xs lenlist = takeWhile not (zipWith elem xs accs) in takeMatch lenlist xs {- Alternative to Data.Set.minView in GHC-6.6. -} choose :: Set a -> Maybe a choose set = toMaybe (not (Set.null set)) (Set.findMin set) keepEssentials :: T i -> T i keepEssentials = filter isEssential -- is more lazy than (length cyc > 1) isEssential :: Cycle i -> Bool isEssential = not . null . drop 1 inverse :: T i -> T i inverse = map reverse