module Sym.Internal.SubSeq
(
module Sym.Internal.CLongArray
, SubSeq
, choose
) where
import Sym.Internal.CLongArray
import Foreign
import Foreign.C.Types
import System.IO.Unsafe
type SubSeq = CLongArray
class (Bits a, Integral a) => Bitmask a where
next :: a -> a
ones :: a -> SubSeq
ones m = fromList . take (popCount m) $ filter (testBit m) [0..]
instance Bitmask CLong where
next = nextCLong
ones = onesCLong
instance Bitmask Integer where
next = nextIntegral
bitmasks :: Bitmask a => Int -> Int -> [a]
bitmasks n k = take binomial (iterate next ((1 `shiftL` k) 1))
where
n' = toInteger n
k' = toInteger k
binomial = fromIntegral $ product [n', n'1 .. n'k'+1] `div` product [1..k']
choose :: Int -> Int -> [SubSeq]
choose n k
| n <= 32 = map ones (bitmasks n k :: [CLong])
| otherwise = map ones (bitmasks n k :: [Integer])
foreign import ccall unsafe "bit.h next" c_next :: CLong -> CLong
nextCLong :: CLong -> CLong
nextCLong = c_next
foreign import ccall unsafe "bit.h ones" c_ones :: Ptr CLong -> CLong -> IO ()
onesCLong :: CLong -> CLongArray
onesCLong m = unsafePerformIO . unsafeNew (popCount m) $ flip c_ones m
nextIntegral :: (Integral a, Bits a) => a -> a
nextIntegral a =
let b = (a .|. (a 1)) + 1
in b .|. ((((b .&. (b)) `div` (a .&. (a))) `shiftR` 1) 1)