{-# OPTIONS_GHC -fglasgow-exts #-}
module Permute (
tests_Permute
) where
import Control.Monad.ST
import Data.Array.ST
import Data.List( foldl' )
import qualified Data.List as List
import Data.Maybe( fromJust )
import qualified Data.Set as Set
import Data.Permute
import Driver
import Test.QuickCheck
import Test.Permute()
import qualified Test.Permute as Test
prop_size_permute (Nat n) =
size (permute n) == n
prop_elems_permute (Nat n) =
elems (permute n) == [0..(n-1)]
prop_size_listPermute (ListPermute n is) =
size (listPermute n is) == n
prop_elems_listPermute (ListPermute n is) =
elems (listPermute n is) == is
prop_size_swapsPermute (SwapsPermute n ss) =
size (swapsPermute n ss) == n
prop_elems_swapsPermute (SwapsPermute n ss) =
elems (swapsPermute n ss) == map at [0..(n-1)]
where
at i = foldl' doSwap i $ reverse ss
doSwap k (i,j) | k == i = j
| k == j = i
| otherwise = k
prop_size_cyclesPermute (CyclesPermute n cs) =
size (cyclesPermute n cs) == n
prop_elems_cyclesPermute (CyclesPermute n cs) =
elems (cyclesPermute n cs) == map at [0..(n-1)]
where
at i = foldl' doCycle i cs
doCycle k cyc = case List.findIndex (k==) cyc of
Nothing -> k
Just ind -> cycle cyc !! (ind + 1)
prop_at = prop_at_help at
prop_unsafeAt = prop_at_help unsafeAt
prop_at_help a =
forAll arbitrary $ \(Index n i) ->
forAll (Test.permute n) $ \p ->
a p i == (elems p) !! i
prop_indexOf =
forAll arbitrary $ \(Index n x) ->
forAll (Test.permute n) $ \p ->
at p (indexOf p x) == x
prop_size_inverse (p :: Permute) =
size (inverse p) == size p
prop_elems_inverse (p :: Permute) =
all (\i -> is' !! (at p i) == i) [0..(n-1)]
where
n = size p
is' = elems (inverse p)
prop_swaps (Nat n) =
forAll (Test.permute n) $ \p ->
forAll (vector n) $ \xs ->
let xs' = applySwaps (swaps p) xs
in all (\i -> xs' !! i == xs !! (at p i)) [0..(n-1)]
prop_invSwaps (Nat n) =
forAll (Test.permute n) $ \p ->
forAll (vector n) $ \xs ->
let xs' = applySwaps (invSwaps p) xs
in all (\i -> xs' !! (at p i) == xs !! i) [0..(n-1)]
prop_swaps_inverse (Nat n) =
forAll (Test.permute n) $ \p ->
forAll (vector n) $ \xs ->
applySwaps (swaps $ inverse p) xs == (applySwaps (invSwaps p) xs)
prop_invSwaps_inverse (Nat n) =
forAll (Test.permute n) $ \p ->
forAll (vector n) $ \xs ->
applySwaps (invSwaps $ inverse p) xs == (applySwaps (swaps p) xs)
prop_prev_permute (Nat n) =
prev (permute n) == Nothing
prop_next_last (Nat n) =
next (listPermute n $ reverse [0..(n-1)]) == Nothing
prop_next_prev (p :: Permute) =
case prev p of
Just p' -> p == (fromJust $ next p')
Nothing -> p == permute n
where
n = size p
prop_prev_next (p :: Permute) =
case next p of
Just p' -> p == (fromJust $ prev p')
Nothing -> p == (listPermute n $ reverse [0..(n-1)])
where
n = size p
prop_fst_sort (Sort n xs) = let
ys = take n xs
in (fst . sort n) xs == (List.sort ys)
prop_snd_sort (Sort n xs) = let
ys = take n xs
in applySwaps (swaps $ snd $ sort n xs) ys == (List.sort ys)
prop_fst_sortBy (SortBy cmp n xs) = let
ys = take n xs
in (fst . sortBy cmp n) xs == (List.sortBy cmp ys)
prop_snd_sortBy (SortBy cmp n xs) = let
ys = take n xs
in applySwaps (swaps $ snd $ sortBy cmp n xs) ys == (List.sortBy cmp ys)
prop_order (Sort n xs) = let
ys = take n xs
in applySwaps (swaps $ order n xs) ys == (List.sort ys)
prop_orderBy (SortBy cmp n xs) = let
ys = take n xs
in applySwaps (swaps $ orderBy cmp n xs) ys == (List.sortBy cmp ys)
prop_rank (Sort n xs) = let
ys = take n xs
in applySwaps (invSwaps $ rank n xs) ys == (List.sort ys)
prop_rankBy (SortBy cmp n xs) = let
ys = take n xs
in applySwaps (invSwaps $ rankBy cmp n xs) ys == (List.sortBy cmp ys)
prop_swapsPermute_swaps (p :: Permute) =
swapsPermute (size p) (swaps p) == p
prop_isEven_permute (Nat n) =
isEven (permute n)
prop_isEven_swaps (p :: Permute) =
isEven p == even (length (swaps p))
prop_cyclesPermute_cycles (p :: Permute) =
cyclesPermute (size p) (cycles p) == p
prop_cycles_cycleFrom (p :: Permute) =
let n = size p
cycles1 = Set.fromList (map Set.fromList (cycles p))
cycles2 = Set.fromList [Set.fromList (cycleFrom p i) | i <- [0..(n-1)]]
in cycles1 == cycles2
prop_cycles_wholerange (p :: Permute) =
let n = size p
in List.sort (concat (cycles p)) == [0..(n-1)]
prop_period_permute (Nat n) =
period (permute n) == 1
prop_period_onecycle (Nat n) =
n >= 1 ==> period (listPermute n $ [1..(n-1)] ++ [0]) == toInteger n
tests_Permute =
[ ("size . permute" , mytest prop_size_permute)
, ("elems . permute" , mytest prop_elems_permute)
, ("size . listPermute" , mytest prop_size_listPermute)
, ("elems . listPermute" , mytest prop_elems_listPermute)
, ("size . swapsPermute" , mytest prop_size_swapsPermute)
, ("elems . swapsPermute" , mytest prop_elems_swapsPermute)
, ("size . cyclesPermute" , mytest prop_size_cyclesPermute)
, ("elems . cyclesPermute" , mytest prop_elems_cyclesPermute)
, ("at" , mytest prop_at)
, ("unsafeAt" , mytest prop_unsafeAt)
, ("indexOf" , mytest prop_indexOf)
, ("size . inverse" , mytest prop_size_inverse)
, ("elems . inverse" , mytest prop_elems_inverse)
, ("swaps" , mytest prop_swaps)
, ("invSwaps" , mytest prop_invSwaps)
, ("swaps . inverse" , mytest prop_swaps_inverse)
, ("invSwaps . inverse" , mytest prop_invSwaps_inverse)
, ("prev . permute" , mytest prop_prev_permute)
, ("next (last permutation)" , mytest prop_next_last)
, ("next . prev" , mytest prop_next_prev)
, ("prev . next" , mytest prop_prev_next)
, ("fst . sort" , mytest prop_fst_sort)
, ("snd . sort" , mytest prop_snd_sort)
, ("fst . sortBy" , mytest prop_fst_sortBy)
, ("snd . sortBy" , mytest prop_snd_sortBy)
, ("order" , mytest prop_order)
, ("orderBy" , mytest prop_orderBy)
, ("rank" , mytest prop_rank)
, ("rankBy" , mytest prop_rankBy)
, ("swapsPermute . swaps" , mytest prop_swapsPermute_swaps)
, ("isEven . permute" , mytest prop_isEven_permute)
, ("isEven == even . swaps" , mytest prop_isEven_swaps)
, ("cyclesPermute . cycles" , mytest prop_cyclesPermute_cycles)
, ("cycles == all cycleFrom" , mytest prop_cycles_cycleFrom)
, ("concat . cycles == [0..n]" , mytest prop_cycles_wholerange)
, ("period . permute" , mytest prop_period_permute)
, ("period [1..n,0] == n" , mytest prop_period_onecycle)
]
applySwaps :: [(Int,Int)] -> [Int] -> [Int]
applySwaps ss xs = runST $ do
arr <- newListArray (0,length xs - 1) xs :: ST s (STUArray s Int Int)
mapM_ (swap arr) ss
getElems arr
where
swap arr (i,j) = do
i' <- readArray arr i
j' <- readArray arr j
writeArray arr j i'
writeArray arr i j'