Skip to content

Commit ec03656

Browse files
authored
Merge pull request #39 from nanonaren/master
in-place calculation of permutations
2 parents d8bc9b9 + df3499a commit ec03656

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,
@@ -995,3 +996,38 @@ partitionUnknown f s
995996
v2' <- unsafeAppend1 v2 i2 x
996997
return (v1, i1, v2', i2+1)
997998

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

412+
-- | Compute the next (lexicographically) permutation of given vector in-place.
413+
-- Returns False when input is the last permtuation
414+
nextPermutation :: (PrimMonad m,Ord e) => MVector (PrimState m) e -> m Bool
415+
{-# INLINE nextPermutation #-}
416+
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
@@ -356,3 +357,8 @@ unsafeMove :: (PrimMonad m, Prim a)
356357
{-# INLINE unsafeMove #-}
357358
unsafeMove = G.unsafeMove
358359

360+
-- | Compute the next (lexicographically) permutation of given vector in-place.
361+
-- Returns False when input is the last permtuation
362+
nextPermutation :: (PrimMonad m,Ord e,Prim e) => MVector (PrimState m) e -> m Bool
363+
{-# INLINE nextPermutation #-}
364+
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)