Skip to content

Commit df3499a

Browse files
committed
in-place calculation of permutations
1 parent 3bc592f commit df3499a

File tree

5 files changed

+70
-2
lines changed

5 files changed

+70
-2
lines changed

Data/Vector/Generic/Mutable.hs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module Data.Vector.Generic.Mutable (
4444
unsafeRead, unsafeWrite, unsafeModify, unsafeSwap, unsafeExchange,
4545

4646
-- * Modifying vectors
47+
nextPermutation,
4748

4849
-- ** Filling and copying
4950
set, copy, move, unsafeCopy, unsafeMove,
@@ -986,3 +987,38 @@ partitionUnknown f s
986987
v2' <- unsafeAppend1 v2 i2 x
987988
return (v1, i1, v2', i2+1)
988989

990+
{-
991+
http://en.wikipedia.org/wiki/Permutation#Algorithms_to_generate_permutations
992+
993+
The following algorithm generates the next permutation lexicographically after
994+
a given permutation. It changes the given permutation in-place.
995+
996+
1. Find the largest index k such that a[k] < a[k + 1]. If no such index exists,
997+
the permutation is the last permutation.
998+
2. Find the largest index l greater than k such that a[k] < a[l].
999+
3. Swap the value of a[k] with that of a[l].
1000+
4. Reverse the sequence from a[k + 1] up to and including the final element a[n]
1001+
-}
1002+
1003+
-- | Compute the next (lexicographically) permutation of given vector in-place.
1004+
-- Returns False when input is the last permtuation
1005+
nextPermutation :: (PrimMonad m,Ord e,MVector v e) => v (PrimState m) e -> m Bool
1006+
nextPermutation v
1007+
| dim < 2 = return False
1008+
| otherwise = do
1009+
val <- unsafeRead v 0
1010+
(k,l) <- loop val (-1) 0 val 1
1011+
if k < 0
1012+
then return False
1013+
else unsafeSwap v k l >>
1014+
reverse (unsafeSlice (k+1) (dim-k-1) v) >>
1015+
return True
1016+
where loop !kval !k !l !prev !i
1017+
| i == dim = return (k,l)
1018+
| otherwise = do
1019+
cur <- unsafeRead v i
1020+
-- TODO: make tuple unboxed
1021+
let (kval',k') = if prev < cur then (prev,i-1) else (kval,k)
1022+
l' = if kval' < cur then i else l
1023+
loop kval' k' l' cur (i+1)
1024+
dim = length v

Data/Vector/Mutable.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module Data.Vector.Mutable (
4444
unsafeRead, unsafeWrite, unsafeModify, unsafeSwap,
4545

4646
-- * Modifying vectors
47+
nextPermutation,
4748

4849
-- ** Filling and copying
4950
set, copy, move, unsafeCopy, unsafeMove
@@ -404,3 +405,8 @@ unsafeMove :: PrimMonad m => MVector (PrimState m) a -- ^ target
404405
{-# INLINE unsafeMove #-}
405406
unsafeMove = G.unsafeMove
406407

408+
-- | Compute the next (lexicographically) permutation of given vector in-place.
409+
-- Returns False when input is the last permtuation
410+
nextPermutation :: (PrimMonad m,Ord e) => MVector (PrimState m) e -> m Bool
411+
{-# INLINE nextPermutation #-}
412+
nextPermutation = G.nextPermutation

Data/Vector/Primitive/Mutable.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ module Data.Vector.Primitive.Mutable (
4444
unsafeRead, unsafeWrite, unsafeModify, unsafeSwap,
4545

4646
-- * Modifying vectors
47+
nextPermutation,
4748

4849
-- ** Filling and copying
4950
set, copy, move, unsafeCopy, unsafeMove
@@ -342,3 +343,8 @@ unsafeMove :: (PrimMonad m, Prim a)
342343
{-# INLINE unsafeMove #-}
343344
unsafeMove = G.unsafeMove
344345

346+
-- | Compute the next (lexicographically) permutation of given vector in-place.
347+
-- Returns False when input is the last permtuation
348+
nextPermutation :: (PrimMonad m,Ord e,Prim e) => MVector (PrimState m) e -> m Bool
349+
{-# INLINE nextPermutation #-}
350+
nextPermutation = G.nextPermutation

Data/Vector/Unboxed/Mutable.hs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ module Data.Vector.Unboxed.Mutable (
4848
unsafeRead, unsafeWrite, unsafeModify, unsafeSwap,
4949

5050
-- * Modifying vectors
51+
nextPermutation,
5152

5253
-- ** Filling and copying
5354
set, copy, move, unsafeCopy, unsafeMove
@@ -294,6 +295,11 @@ unsafeMove :: (PrimMonad m, Unbox a)
294295
{-# INLINE unsafeMove #-}
295296
unsafeMove = G.unsafeMove
296297

298+
-- | Compute the next (lexicographically) permutation of given vector in-place.
299+
-- Returns False when input is the last permtuation
300+
nextPermutation :: (PrimMonad m,Ord e,Unbox e) => MVector (PrimState m) e -> m Bool
301+
{-# INLINE nextPermutation #-}
302+
nextPermutation = G.nextPermutation
303+
297304
#define DEFINE_MUTABLE
298305
#include "unbox-tuple-instances"
299-

tests/Tests/Move.hs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ import Test.QuickCheck.Property (Property(..))
66

77
import Utilities ()
88

9+
import Control.Monad (replicateM)
10+
import Control.Monad.ST (runST)
11+
import Data.List (sort,permutations)
12+
913
import qualified Data.Vector.Generic as G
1014
import qualified Data.Vector.Generic.Mutable as M
1115

@@ -28,8 +32,18 @@ testMove v = G.length v > 0 ==> (MkProperty $ do
2832
actual <- return $ G.modify (\ mv -> M.move (M.slice dstOff len mv) (M.slice srcOff len mv)) v
2933
unProperty $ counterexample ("Move: " ++ show (v, dstOff, srcOff, len)) (expected == actual))
3034

35+
checkPermutations :: Int -> Bool
36+
checkPermutations n = runST $ do
37+
vec <- U.thaw (U.fromList [1..n])
38+
res <- replicateM (product [1..n]) $ M.nextPermutation vec >> U.freeze vec >>= return . U.toList
39+
return $! ([1..n] : res) == sort (permutations [1..n]) ++ [[n,n-1..1]]
40+
41+
testPermutations :: Bool
42+
testPermutations = all checkPermutations [1..7]
43+
3144
tests =
3245
[testProperty "Data.Vector.Mutable (Move)" (testMove :: V.Vector Int -> Property),
3346
testProperty "Data.Vector.Primitive.Mutable (Move)" (testMove :: P.Vector Int -> Property),
3447
testProperty "Data.Vector.Unboxed.Mutable (Move)" (testMove :: U.Vector Int -> Property),
35-
testProperty "Data.Vector.Storable.Mutable (Move)" (testMove :: S.Vector Int -> Property)]
48+
testProperty "Data.Vector.Storable.Mutable (Move)" (testMove :: S.Vector Int -> Property),
49+
testProperty "Data.Vector.Generic.Mutable (nextPermutation)" testPermutations]

0 commit comments

Comments
 (0)