{-#LANGUAGE DeriveDataTypeable, TemplateHaskell #-}
module Test.Feat.Enumerate (
Index,
Enumerate(..),
parts,
fromParts,
RevList(..),
toRev,
Finite(..),
fromFinite,
module Data.Monoid,
union,
module Control.Applicative,
cartesian,
singleton,
pay,
) where
import Control.Sized
import Control.Applicative
import Data.Semigroup
import Data.Monoid hiding ((<>))
import Data.Typeable
import Data.List(transpose)
import Test.Feat.Finite
type Part = Int
data Enumerate a = Enumerate
{ revParts :: RevList (Finite a)
} deriving Typeable
parts :: Enumerate a -> [Finite a]
parts = fromRev . revParts
fromParts :: [Finite a] -> Enumerate a
fromParts ps = Enumerate (toRev ps)
instance Functor Enumerate where
fmap f e = Enumerate (fmap (fmap f) $ revParts e)
instance Applicative Enumerate where
pure = singleton
f <*> a = fmap (uncurry ($)) (cartesian f a)
instance Alternative Enumerate where
empty = Enumerate mempty
(<|>) = union
instance Sized Enumerate where
pay e = Enumerate (revCons mempty $ revParts e)
aconcat = mconcat
pair = cartesian
fin k = fromParts [finFin k]
instance Semigroup (Enumerate a) where
(<>) = union
instance Monoid (Enumerate a) where
mempty = empty
mappend = union
mconcat = econcat
econcat :: [Enumerate a] -> Enumerate a
econcat [] = mempty
econcat [a] = a
econcat [a,b] = union a b
econcat xs = Enumerate
(toRev . map mconcat . transpose $ map parts xs)
cartesian (Enumerate xs1) (Enumerate xs2) = Enumerate (xs1 `prod` xs2)
prod :: RevList (Finite a) -> RevList (Finite b) -> RevList (Finite (a,b))
prod (RevList [] _) _ = mempty
prod (RevList xs0@(_:xst) _) (RevList _ rys0) = toRev$ prod' rys0 where
prod' [] = []
prod' (ry:rys) = go ry rys where
go ry rys = conv xs0 ry : case rys of
(ry':rys') -> go ry' rys'
[] -> prod'' ry xst
prod'' :: [Finite b] -> [Finite a] -> [Finite (a,b)]
prod'' ry = go where
go [] = []
go xs@(_:xs') = conv xs ry : go xs'
conv :: [Finite a] -> [Finite b] -> Finite (a,b)
conv xs ys = Finite
(sum $ zipWith (*) (map fCard xs) (map fCard ys ))
(prodSel xs ys)
prodSel :: [Finite a] -> [Finite b] -> (Index -> (a,b))
prodSel (f1:f1s) (f2:f2s) = \i ->
let mul = fCard f1 * fCard f2
in if i < mul
then let (q, r) = (i `quotRem` fCard f2)
in (fIndex f1 q, fIndex f2 r)
else prodSel f1s f2s (i-mul)
prodSel _ _ = \i -> error "index out of bounds"
union :: Enumerate a -> Enumerate a -> Enumerate a
union (Enumerate xs1) (Enumerate xs2) = Enumerate (xs1 `mappend` xs2)
singleton :: a -> Enumerate a
singleton a = Enumerate (revPure $ pure a)
data RevList a = RevList {fromRev :: [a], reversals :: [[a]]} deriving Show
instance Functor RevList where
fmap f = toRev . fmap f . fromRev
instance Semigroup a => Semigroup (RevList a) where
(<>) xs ys = toRev $ zipMon (fromRev xs) (fromRev ys) where
zipMon :: Semigroup a => [a] -> [a] -> [a]
zipMon (x:xs) (y:ys) = x <> y : zipMon xs ys
zipMon xs ys = xs ++ ys
instance (Monoid a, Semigroup a) => Monoid (RevList a) where
mempty = toRev[]
mappend = (<>)
toRev:: [a] -> RevList a
toRev xs = RevList xs $ go [] xs where
go _ [] = []
go rev (x:xs) = let rev' = x:rev in rev' : go rev' xs
revCons a = toRev. (a:) . fromRev
revPure a = RevList [a] [[a]]