module MagicHaskeller.Classify(randomTestFilter, filterBF, filterRc, filterDB
, ofilterDB, opreexecute, CmpBot, cmpBot, cmpBotIO
, FiltrableBF
) where
#define CHTO
import Control.Monad.Search.Combinatorial
import Data.Maybe
import Control.Monad(mplus)
import MagicHaskeller.Instantiate
import GHC.Exts(unsafeCoerce#)
import MagicHaskeller.Execute(unsafeExecute)
import MagicHaskeller.TyConLib
import MagicHaskeller.Types
import MagicHaskeller.DebMT
import MagicHaskeller.MyDynamic
#ifdef CHTO
import System.IO.Unsafe
import MagicHaskeller.TimeOut
import Control.Concurrent(yield)
import Data.IORef
#endif
import MagicHaskeller.T10(mergesortWithBy, mergeWithBy, mergesortWithByBot, mergeWithByBot, diffSortedBy, diffSortedByBot)
#ifdef DEBUG
import Test.QuickCheck
#endif
import MagicHaskeller.Expression
import MagicHaskeller.ProgramGenerator
import MagicHaskeller.Options
import Language.Haskell.TH.Ppr
import System.IO
trace str e = e
randomTestFilter md = filterBF (extractTCL md) (extractRTrie md) (opt $ extractCommon md)
filterBF :: FiltrableBF m => TyConLib -> RTrie -> Opt () -> Type -> m AnnExpr -> m AnnExpr
filterBF tcl rtrie pto typ
= case trace (show typ) $
typeToRandomsOrd tcl rtrie typ of
Nothing -> id
Just ([], op) -> fmap snd . ofilter (op,pto) . fmap opreexecute
Just (rnds,op) -> fmap snd . sfilter (op,pto) . fmap (spreexecute (uncurryDyn (mkUncurry tcl) typ) rnds)
spreexecute uncurrier rnds e@(AE _ dyn) = let f = uncurrier dyn in (map (dynAppErr "in Classify.spreexecute" f) rnds, e)
opreexecute :: AnnExpr -> (Dynamic, AnnExpr)
opreexecute e@(AE _ dyn) = (dyn, e)
unscanl :: Ord e => Matrix e -> Matrix e
unscanl = unscanlBy compare
type CmpBot k = (k->k->Ordering, Opt ())
class Search m => FiltrableBF m where
sfilter :: CmpBot k -> m ([k],e) -> m ([k],e)
ofilter :: CmpBot k -> m (k,e) -> m (k,e)
instance FiltrableBF Matrix where
sfilter = sfilterMx
ofilter = ofilterMx
instance FiltrableBF Recomp where
sfilter = sfilterRc
ofilter = ofilterRc
instance FiltrableBF DBound where
sfilter = sfilterDB
ofilter = ofilterDB
sfilterMx :: CmpBot k -> Matrix ([k],e) -> Matrix ([k],e)
sfilterMx op mx = trace "sfilterMx" $
unscanlByList op $ repEqClsBy op mx
filterDB :: TyConLib -> RTrie -> Opt () -> Type -> DBound AnnExpr -> DBound AnnExpr
filterDB = filterBF
filterRc :: TyConLib -> RTrie -> Opt () -> Type -> Recomp AnnExpr -> Recomp AnnExpr
filterRc = filterBF
sfilterRc :: CmpBot k -> Recomp ([k],e) -> Recomp ([k],e)
sfilterRc op mx = trace "sfilter" $
unscanlByListRc op $ repEqClsByRc op mx
unscanlByList :: CmpBot k -> Matrix ([k],e) -> Matrix ([k],e)
unscanlByList op mx = case unMx mx of yss@(xs:xss) -> Mx (xs : zipWith3 (deleteListByList op) (tcnrnds op) xss yss)
unscanlByListMx :: CmpBot k -> Matrix ([k],e) -> Matrix ([k],e)
unscanlByListMx op mx = zipDepth3Mx (\dep -> deleteListByList op (fcnrnd op (1+dep))) mx (delay mx)
unscanlByListRc :: CmpBot k -> Recomp ([k],e) -> Recomp ([k],e)
unscanlByListRc op rc = zipDepth3Rc (\dep -> deleteListByList op (fcnrnd op (1+dep))) rc (delay rc)
deleteListByList cmp len xs ys = dlbBot (liftCompareBot len cmp) xs ys
comparers :: Int -> CmpBot a -> [([a],e) -> ([a],e) -> Maybe Ordering]
comparers m cmp = liftCompareBot m cmp : comparers (m+1) cmp
liftCompare :: Int -> (a->a->Ordering) -> ([a],e) -> ([a],e) -> Ordering
liftCompare m cmp (xs,_) (ys,_) = liftCmp m cmp xs ys
liftCmp :: Int -> (a->a->Ordering) -> [a] -> [a] -> Ordering
liftCmp 0 cmp xs ys = EQ
liftCmp _ _ [] [] = EQ
liftCmp len cmp (x:xs) (y:ys) = trace "liftCmp" $
case cmp x y of
EQ -> trace "just eq" $
liftCmp (len1) cmp xs ys
c -> trace "otherwise"
c
liftCompareBot :: Int -> CmpBot a -> ([a],e) -> ([a],e) -> Maybe Ordering
liftCompareBot m cmp (xs,_) (ys,_) = liftCmpBot m cmp xs ys
liftCmpBot :: Int -> CmpBot a -> [a] -> [a] -> Maybe Ordering
#ifdef CHTO
liftCmpBot len (cmp,pto) xs ys = unsafeWithPTOOpt pto $ liftCmp len cmp xs ys
cmpBot (cmp,pto) x y = unsafeWithPTOOpt pto $ cmp x y
cmpBotIO (cmp,pto) x y = maybeWithTOOpt pto $ return $! cmp x y
#else
liftCmpBot len (cmp,_pto) xs ys = Just $ liftCmp len cmp xs ys
cmpBot (cmp,_pto) x y = Just $ cmp x y
cmpBotIO (cmp,pto) x y = return $ Just $ cmp x y
#endif
dlbBot cmps xs ys = diffSortedByBot cmps xs ys
dlb cmps xs ys = diffSortedBy cmps xs ys
repEqClsBy_simple :: CmpBot k -> Matrix ([k],e) -> Matrix ([k],e)
repEqClsBy_simple cmp mx = Mx $ zipWith (\dep ys -> mergesortWithByBot const (liftCompareBot dep cmp) ys) (cnrnds cmp) $ unMx $ scanl1BF mx
repEqClsByMx :: CmpBot k -> Matrix ([k],e) -> Matrix ([k],e)
repEqClsByMx cmp mx = zipDepthMx (\dep ys -> let n = fcnrnd cmp dep in mergesortWithByBot const (liftCompareBot n cmp) ys) $ scanl1BF mx
repEqClsByRc :: CmpBot k -> Recomp ([k],e) -> Recomp ([k],e)
repEqClsByRc cmp mx = zipDepthRc (\dep ys -> let n = fcnrnd cmp dep in mergesortWithByBot const (liftCompareBot n cmp) ys) $ scanl1BF mx
eqClsBy_naive :: CmpBot a -> Matrix ([a],b) -> Matrix [([a],b)]
eqClsBy_naive cmp (Mx xss) = Mx $ zipWith (\dep ys -> ys /// liftCompareBot dep cmp) (cnrnds cmp) $ scanl1 (++) xss
fcnrnd (_,opt) = fcnrand opt
cnrnds tup = map (fcnrnd tup) [0..]
tcnrnds tup = map (fcnrnd tup) [1..]
repEqClsBy :: CmpBot k -> Matrix ([k],e) -> Matrix ([k],e)
repEqClsBy cmp = trace "repEqClsBy" .
fmap head . eqClsBy cmp
eqClsBy :: CmpBot a -> Matrix ([a],b) -> Matrix [([a],b)]
eqClsBy cb@(cmp,opt) mx = Mx $
scanl (\xs (n,ys) -> mergeBy (liftCompareBot n cb) (eqClsByNth cmp n xs) ys) ecb0 $ zip (tcnrnds cb) ecbs
where Mx (ecb0:ecbs) = eqClsByFstNs cb mx
eqClsByNth :: (a->a->Ordering) -> Int -> [[([a],e)]] -> [[([a],e)]]
eqClsByNth cmp n = concatMap ((/// (\ (xs,_) (ys,_) -> Just $ cmp (xs!!(n1)) (ys!!(n1)))))
eqClsByFstNs :: CmpBot a -> Matrix ([a],b) -> Matrix [([a],b)]
eqClsByFstNs cmp (Mx tss) = Mx $ zipWith eqClsByFstN (cnrnds cmp) tss
where eqClsByFstN n = (/// liftCompareBot n cmp)
isLongEnough 0 _ = True
isLongEnough _ [] = False
isLongEnough n (x:xs) = isLongEnough (n1) xs
filterEligibles :: Int -> [([k],e)] -> [([k],e)]
#ifdef CHTO
filterEligibles n = filter (isLongEnough n . fst)
#else
filterEligibles _ = id
#endif
mergeBy :: (k -> k -> Maybe Ordering) -> [[k]] -> [[k]] -> [[k]]
mergeBy cmp = mergeWithByBot (++) (\x y -> head x `cmp` head y)
sfilterDB :: CmpBot k -> DBound ([k],e) -> DBound ([k],e)
sfilterDB cmp (DB f) = DB $ \n -> mergesortWithByBot (\x@(_,i) y@(_,j) -> if i<j then y else x) (\(k,_) (l,_) -> liftCompareBot (fcnrnd cmp n) cmp k l) (f n)
ofilterDB :: CmpBot k -> DBound (k,e) -> DBound (k,e)
ofilterDB cmp (DB f) = DB $ \n -> mergesortWithByBot const (\((k,_),_) ((l,_),_) -> cmpBot cmp k l) (f n)
ofilterRc :: CmpBot k -> Recomp (k,e) -> Recomp (k,e)
ofilterRc cmp rc = let sorted = mapDepth (mergesortWithByBot const op) rc
cumulative = scanlRc (mergeWithByBot const op) [] sorted
in zipDepth3Rc (\_ -> diffSortedByBot op) sorted cumulative
where op (k,_) (l,_) = cmpBot cmp k l
ofilterMx :: CmpBot k -> Matrix (k,e) -> Matrix (k,e)
ofilterMx cmp (Mx xss) = let sorted = map (mergesortWithByBot const op) xss
cumulative = scanl (mergeWithByBot const op) [] sorted
in Mx $ zipWith (diffSortedByBot op) sorted cumulative
where op (k,_) (l,_) = cmpBot cmp k l
unscanlBy :: (k->k->Ordering) -> Matrix k -> Matrix k
unscanlBy op (Mx yss@(xs:xss)) = Mx (xs : zipWith (diffSortedBy op) xss yss)
(///) :: [a] -> (a->a->Maybe Ordering) -> [[a]]
ts /// cmp = mergesortWithByBot (++) (\x y -> head x `cmp` head y) $ map return ts
#ifdef DEBUG
prop_sfilter_exhaustive = \yss -> all longenough (concat yss) && unique (concat yss) && length yss < 6 ==> let xss = map (map (\x -> (x,()))) yss in length (concat $ take 10 $ unMx $ sfilter (compare,Nothing) $ Mx (xss ++ repeat [])) == length (concat xss :: [([Int],())])
type Propsf a = [[[a]]] -> Property
prop_sfilter :: Ord a => Int -> Propsf a
prop_sfilter m = \yss -> length yss < m && all longenough (concat yss) ==> let xss = map (map (\x -> (x,()))) yss in (concat xss /// liftCompareBot m (compare,Nothing)) == (concat (take m (unMx $ sfilter (compare,Nothing) (Mx (xss ++ repeat [])))) /// liftCompareBot m (compare,Nothing))
unique [] = True
unique (x:xs) = all (/=x) xs && unique xs
longenough ks = length ks > 3+ncmp
#endif