module Math.SetCover.Exact (
Assign(..), assign, bitVectorFromSetAssigns,
partitions, search, step,
State(..), initState, updateState,
Set(..),
) where
import qualified Math.SetCover.IntSet as IntSetX
import qualified Math.SetCover.BitMap as BitMap
import qualified Math.SetCover.BitSet as BitSet
import qualified Math.SetCover.Bit as Bit
import Control.Applicative ((<$>), (<$))
import qualified Data.IntSet as IntSet
import qualified Data.Map as Map
import qualified Data.Set as Set
import qualified Data.List as List
import qualified Data.List.Match as Match
import qualified Data.Foldable as Fold
import Data.Maybe.HT (toMaybe)
import Data.Bits (setBit)
import Prelude hiding (null)
class Set set where
null :: set -> Bool
disjoint :: set -> set -> Bool
unions :: [set] -> set
difference :: set -> set -> set
minimize :: set -> [Assign label set] -> [Assign label set]
instance (Ord a) => Set (Set.Set a) where
null = Set.null
disjoint x y = Set.null $ Set.intersection x y
unions = Set.unions
difference = Set.difference
minimize free =
Fold.minimumBy Match.compareLength .
foldr (Map.unionWith (++)) (constMap [] free) .
map (\a -> constMap [a] $ labeledSet a)
{-# INLINE constMap #-}
constMap :: (Ord a) => b -> Set.Set a -> Map.Map a b
constMap a = Fold.foldMap (flip Map.singleton a)
instance (Ord k, Set a) => Set (Map.Map k a) where
null = Map.null
disjoint x y = Fold.and $ Map.intersectionWith disjoint x y
unions =
fmap unions . foldr (Map.unionWith (++)) Map.empty . map (fmap (:[]))
difference =
Map.differenceWith
(\x y -> let z = difference x y in toMaybe (not $ null z) z)
minimize free asns =
map label $
Fold.minimumBy Match.compareLength $
Map.intersectionWith minimize free $
foldr (Map.unionWith (++)) ([] <$ free) $
map (\asn -> (:[]) . assign asn <$> labeledSet asn) asns
instance (Bit.C a) => Set (BitSet.Set a) where
null = BitSet.null
disjoint = BitSet.disjoint
unions = Fold.fold
difference = BitSet.difference
minimize free available =
let singleMin =
BitSet.keepMinimum $ BitMap.minimumSet free $
Fold.foldMap (BitMap.fromSet . labeledSet) available
in filter (not . BitSet.disjoint singleMin . labeledSet) available
instance Set IntSet.IntSet where
null = IntSet.null
disjoint x y = IntSet.null $ IntSet.intersection x y
unions = IntSet.unions
difference = IntSet.difference
minimize free available =
let bitset = BitSet.Set . IntSetX.fromIntSet
singleMin =
(\(BitSet.Set s) -> IntSetX.findMin s) $
BitMap.minimumSet (bitset free) $
Fold.foldMap (BitMap.fromSet . bitset . labeledSet) available
in filter (IntSet.member singleMin . labeledSet) available
data Assign label set =
Assign {
label :: label,
labeledSet :: set
}
assign :: label -> set -> Assign label set
assign = Assign
bitVectorFromSetAssigns ::
(Ord a) =>
[Assign label (Set.Set a)] -> [Assign label (BitSet.Set Integer)]
bitVectorFromSetAssigns asns =
let mapToInt =
Map.fromList $ zip (Set.toList $ unions $ map labeledSet asns) [0..]
err = error "bitVectorFromSetAssigns: element disappeared"
bitVec =
Fold.foldl' setBit 0 .
map (flip (Map.findWithDefault err) mapToInt) .
Set.toList
in map (fmap (BitSet.Set . bitVec)) asns
data State label set =
State {
availableSubsets :: [Assign label set],
freeElements :: set,
usedSubsets :: [Assign label set]
}
instance Functor (Assign label) where
fmap f (Assign lab set) = Assign lab (f set)
instance Functor (State label) where
fmap f (State ab fp pb) =
State (map (fmap f) ab) (f fp) (map (fmap f) pb)
initState :: Set set => [Assign label set] -> State label set
initState subsets =
State {
availableSubsets = subsets,
freeElements = unions $ map labeledSet subsets,
usedSubsets = []
}
{-# INLINE updateState #-}
updateState :: Set set => Assign label set -> State label set -> State label set
updateState attempt@(Assign _ attemptedSet) s =
State {
availableSubsets =
filter (disjoint attemptedSet . labeledSet) $
availableSubsets s,
freeElements = difference (freeElements s) attemptedSet,
usedSubsets = attempt : usedSubsets s
}
{-# INLINE step #-}
step :: Set set => State label set -> [State label set]
step s =
if List.null (availableSubsets s) || null (freeElements s)
then []
else
map (flip updateState s) $
minimize (freeElements s) (availableSubsets s)
{-# INLINE search #-}
search :: Set set => State label set -> [[label]]
search s =
if null (freeElements s)
then [map label $ usedSubsets s]
else step s >>= search
{-# INLINE partitions #-}
partitions :: Set set => [Assign label set] -> [[label]]
partitions = search . initState