radix-tree-1.0.0.0: test/properties/Test/RadixNTree/Word8/Sample.hs
{-# LANGUAGE RankNTypes #-}
module Test.RadixNTree.Word8.Sample
( Sample
, zero
, one
, tip
, bin
, tiny
, small
, medium
--, large
, mkUnary0
, mkUnary1
, mkUnary2
, mkBinary
, mkBinaryL
, mkEqual
, mkSuperset
, mkSubset
) where
import No.Tree (NoTree)
import qualified No.Tree as No
import Test.Kit
import Test.Random
import Data.List.NonEmpty (NonEmpty (..))
import qualified Data.List.NonEmpty as NonEmpty
import Data.Word
import System.Random
data Trees = Trees (NonEmpty Tree)
| End
deriving Show
data Tree = Tree
(NonEmpty Word8)
Bool -- ^ Whether this point is a separate key in the tree
Trees
deriving Show
genTrees
:: RandomGen g
=> Int -- ^ Maximum branches on each level
-> Int -- ^ Maximum number of segments
-> Int -- ^ Maximum segment length
-> Int -- ^ Maximum total length
-> g
-> (Trees, g)
genTrees nB nL nS nT = broad nL nT
where
broad count len g0
| len <= 0 || count <= 0 = (End, g0)
| otherwise =
let ~(n, g1) = uniformR (1, nB) g0
~(as, g2) = list1 (deep count len) n g1
in (Trees $ dedup as, g2)
dedup = NonEmpty.nubBy (\(Tree (x :| _) _ _) (Tree (y :| _) _ _) -> x == y)
deep count len g0 =
let ~(n, g1) = uniformR (1, max 1 (min len nS)) g0
~(xs, g2) = list1 uniform n g1
~(t, g3) = broad (count - 1) (len - n) g2
~(bias, g4) = case t of
End -> (nL, g3)
_ -> uniformR (1, nL) g3
in (Tree xs (bias == 1) t, g4)
timber :: Trees -> [([Word8], Int)]
timber = fst . broad id ([], 1)
where
broad pre ~(acc, n) End = ((pre [], n) : acc, n + 1)
broad pre z (Trees ts) = foldr (flip $ deep pre) z ts
deep pre z@(acc, n) (Tree xs real t) =
let z' = if real
then ((pre $ NonEmpty.toList xs, n) : acc, n + 1)
else z
in broad (pre . (NonEmpty.toList xs <>)) z' t
data Sample = Sample
[(No.Openness, [Word8], Int)] -- ^ Keys in the dictionary
[(No.Openness, [Word8], Int)] -- ^ Keys not in the dictionary
deriving Show
halve :: [a] -> ([a], [a])
halve (a:b:cs) = let ~(xs, ys) = halve cs
in (a:xs, b:ys)
halve a = (a, [])
sample :: RandomGen g => Trees -> g -> Sample
sample t g0 =
let ~(xs, g1) = shuffle (timber t) g0
~(os, g2) = list (\g' -> let ~(b, g'') = uniform g'
in ( if b then No.Open else No.Closed
, g''
)
)
(length xs) g1
xs' = zipWith (\a (b, c) -> (a, b, c)) os xs
~(ys, zs) = halve xs'
~(z, _) = uniform g2
as | z = case ys of
[] -> []
(b, _, i) : rest -> (b, [], i) : rest
| otherwise = ys
bs = case zs of
[] -> []
(b, _, i) : rest -> (b, [], i) : rest
in Sample as bs
zero, one, tip, bin :: Sample
zero = Sample []
[ (No.Open, [], 1), (No.Closed, [1, 2, 3], 2), (No.Open, [3, 2, 1], 3) ]
one = Sample [(No.Open, [1, 2, 3], 0)]
[ (No.Closed, [1, 2, 3], 1), (No.Open, [1, 2, 2], 2), (No.Closed, [1, 2, 4], 3)
, (No.Open, [1, 2], 4), (No.Closed, [1, 2, 3, 4], 5), (No.Open, [2, 3, 4], 6)
, (No.Closed, [], 7), (No.Open, [2], 8)
]
tip = Sample [(No.Open, [], 0)]
[ (No.Closed, [1, 2, 3], 1), (No.Closed, [], 2) ]
bin = Sample [(No.Open, [1, 2, 2, 3], 0), (No.Closed, [1, 2, 4, 5], 1)]
[ (No.Closed, [1, 2, 3, 4], 2), (No.Open, [1, 2, 2, 3], 3)
, (No.Closed, [1, 2, 4, 5], 4), (No.Closed, [], 5)
]
tiny, small, medium :: Sample
tiny = uncurry sample $ genTrees 4 2 4 16 (mkStdGen 2)
small = uncurry sample $ genTrees 4 4 4 16 (mkStdGen 4)
medium = uncurry sample $ genTrees 8 4 4 16 (mkStdGen 16)
type FromList pat = forall x. [([Word8], x)] -> pat x
mkUnary0 :: FromList pat -> Sample -> [Case () (pat Int) (NoTree [Word8] Int)]
mkUnary0 patFromList (Sample xs _) =
let as = fmap (\(_, k, i) -> (k, i)) xs
in [Case () (patFromList as) (No.fromList as)]
mkUnary1
:: FromList pat
-> Sample -> [Case (No.Openness, [Word8], Int) (pat Int) (NoTree [Word8] Int)]
mkUnary1 patFromList (Sample xs ys) =
let as = fmap (\(_, k, i) -> (k, i)) xs
pat = patFromList as
no = No.fromList as
in foldr (\x -> (:) (Case x pat no)) [] $ xs <> ys
mkUnary2
:: FromList pat
-> Sample
-> [Case (No.Openness, [Word8], No.Openness, [Word8], Int) (pat Int) (NoTree [Word8] Int)]
mkUnary2 patFromList (Sample xs ys) =
let xs' = fmap (\(_, k, i) -> (k, i)) xs
pat = patFromList xs'
no = No.fromList xs'
~(as, bs) = halve xs
~(cs, ds) = halve ys
ones = fmap (\(o, a, i) -> (o, a, o, a, i)) $ as <> cs
twos = zipWith (\(o, a, i) (p, b, _) -> (o, a, p, b, i)) bs ds
in foldr (\x -> (:) (Case x pat no)) [] $ ones <> twos
mkBinary
:: FromList pat
-> Sample
-> [Case (pat Int, NoTree [Word8] Int) (pat Int) (NoTree [Word8] Int)]
mkBinary patFromList (Sample xs ys) =
let as = fmap (\(_, k, i) -> (k, i)) xs
bs = fmap (\(_, k, i) -> (k, i)) ys
in [Case (patFromList bs, No.fromList bs) (patFromList as) (No.fromList as)]
mkBinaryL
:: FromList pat
-> Sample
-> [Case (pat Int, NoTree [Word8] Int) (pat Int) (NoTree [Word8] Int)]
mkBinaryL patFromList (Sample xs ys) =
let xs' = fmap (\(_, k, i) -> (k, i)) xs
ys' = fmap (\(_, k, i) -> (k, i)) ys
~(as, _) = halve xs'
~(bs, _) = halve ys'
ls = fmap (\(k, a) -> (k, negate a)) bs <> xs'
rs = fmap (\(k, a) -> (k, negate a)) as <> ys'
in [Case (patFromList rs, No.fromList rs) (patFromList ls) (No.fromList ls)]
mkEqual
:: FromList pat
-> Sample
-> [Case (pat Int, NoTree [Word8] Int) (pat Int) (NoTree [Word8] Int)]
mkEqual patFromList (Sample xs _) =
let as = fmap (\(_, k, i) -> (k, i)) xs
pat = patFromList as
no = No.fromList as
in [Case (pat, no) pat no]
mkSuperset
:: FromList pat
-> Sample
-> [Case (pat Int, NoTree [Word8] Int) (pat Int) (NoTree [Word8] Int)]
mkSuperset patFromList (Sample xs ys) =
let as = fmap (\(_, k, i) -> (k, i)) xs
bs = fmap (\(_, k, i) -> (k, i)) ys
zs = as <> bs
in [Case (patFromList zs, No.fromList zs) (patFromList as) (No.fromList as)]
mkSubset
:: FromList pat
-> Sample
-> [Case (pat Int, NoTree [Word8] Int) (pat Int) (NoTree [Word8] Int)]
mkSubset patFromList (Sample xs ys) =
let as = fmap (\(_, k, i) -> (k, i)) xs
bs = fmap (\(_, k, i) -> (k, i)) ys
zs = as <> bs
in [Case (patFromList as, No.fromList as) (patFromList zs) (No.fromList zs)]