module Math.SetCover.Exact.Block (blocksFromSets) where
import Math.SetCover.EnumMap (constMap)
import qualified Data.List as List
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.Monoid.HT as Mn
import Data.Set (Set)
import Data.Tuple.HT (swap)
import Data.Bits (Bits, bitSize, setBit, shiftL, complement)
blocksFromSets ::
(Ord a, Num block, Bits block) => [Set a] -> ([[block]], [block])
blocksFromSets sets =
let dummyBlock = 0
blockSize = bitSize dummyBlock
complete = Set.unions sets
mapToInt = Map.fromList $ zip (Set.toList complete) [0..]
blocks =
blocksFromInts blockSize .
Map.elems . Map.intersection mapToInt . constMap ()
in (map blocks sets,
case divMod (Set.size complete) blockSize of
(numBlocks,remd) ->
replicate numBlocks (complement 0 `asTypeOf` dummyBlock) ++
Mn.when (remd>0) [shiftL 1 remd 1])
blocksFromInts :: (Num block, Bits block) => Int -> [Int] -> [block]
blocksFromInts blockSize =
zipWith blockFromBits (iterate (blockSize+) 0) . snd .
flip (List.mapAccumL (\elems pivot -> swap $ span (<pivot) elems))
(iterate (blockSize+) blockSize)
blockFromBits :: (Num block, Bits block) => Int -> [Int] -> block
blockFromBits offset = List.foldl' setBit 0 . map (subtract offset)