module Math.SetCover.Exact (
Assign(..), assign,
bitVectorFromSetAssigns, intSetFromSetAssigns,
partitions, search, step,
State(..), initState, updateState,
Set(..),
Tree(..), decisionTree, completeTree,
Choose(..),
) where
import qualified Math.SetCover.BitMap as BitMap
import qualified Math.SetCover.BitSet as BitSet
import qualified Math.SetCover.Bit as Bit
import Math.SetCover.EnumMap (constMap)
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.Match as Match
import qualified Data.List as List
import qualified Data.Foldable as Fold
import Data.Function.HT (compose2)
import Data.Maybe.HT (toMaybe)
import Data.Tuple.HT (mapFst, mapSnd)
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]
class Set set => Choose set where
chooseMinimize :: set -> [Assign label set] -> (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 . histogramSet free
instance (Ord a) => Choose (Set.Set a) where
chooseMinimize free =
mapFst Set.singleton .
List.minimumBy (compose2 Match.compareLength snd) .
Map.toList . histogramSet free
histogramSet ::
Ord k =>
Set.Set k ->
[Assign label (Set.Set k)] ->
Map.Map k [Assign label (Set.Set k)]
histogramSet free =
foldr (Map.unionWith (++)) (constMap [] free) .
map (\a -> constMap [a] $ labeledSet a)
instance (Ord k, Set set) => Set (Map.Map k set) 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 =
map label . Fold.minimumBy Match.compareLength .
Map.intersectionWith minimize free . histogramMap free
instance (Ord k, Choose set) => Choose (Map.Map k set) where
chooseMinimize free =
(\(k,(minSet,asns)) -> (Map.singleton k minSet, map label asns)) .
List.minimumBy (compose2 Match.compareLength (snd.snd)) . Map.toList .
Map.intersectionWith chooseMinimize free . histogramMap free
histogramMap ::
(Ord k, Set set) =>
Map.Map k set ->
[Assign label (Map.Map k set)] ->
Map.Map k [Assign (Assign label (Map.Map k set)) set]
histogramMap free =
foldr (Map.unionWith (++)) ([] <$ free) .
map (\asn -> (:[]) . assign asn <$> labeledSet asn)
instance (Bit.C a) => Set (BitSet.Set a) where
null = BitSet.null
disjoint = BitSet.disjoint
unions = Fold.fold
difference = BitSet.difference
minimize free = snd . chooseMinimize free
instance (Bit.C a) => Choose (BitSet.Set a) where
chooseMinimize free available =
let singleMin =
BitSet.keepMinimum $ BitMap.minimumSet free $
Fold.foldMap (BitMap.fromSet . labeledSet) available
in (singleMin,
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 = snd . chooseMinimize free
instance Choose IntSet.IntSet where
chooseMinimize free available =
let singleMin =
IntSet.findMin $ BitSet.getBits $
BitMap.minimumSet (BitSet.Set free) $
Fold.foldMap (BitMap.fromSet . BitSet.Set . labeledSet) available
in (IntSet.singleton singleMin,
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 bitVec = Fold.foldl' setBit 0 . mapIntFromSet asns
in map (fmap (BitSet.Set . bitVec)) asns
intSetFromSetAssigns ::
(Ord a) => [Assign label (Set.Set a)] -> [Assign label IntSet.IntSet]
intSetFromSetAssigns asns =
let intSet = IntSet.fromList . Map.elems . mapIntFromSet asns
in map (fmap intSet) asns
mapIntFromSet ::
(Ord a) => [Assign label (Set.Set a)] -> Set.Set a -> Map.Map a Int
mapIntFromSet asns =
let mapToInt =
Map.fromList $ zip (Set.toList $ unions $ map labeledSet asns) [0..]
in Map.intersection mapToInt . constMap ()
data State label set =
State {
availableSubsets :: [Assign label set],
freeElements :: set,
usedSubsets :: [label]
}
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) 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 (Assign attemptLabel attemptedSet) s =
State {
availableSubsets =
filter (disjoint attemptedSet . labeledSet) $
availableSubsets s,
freeElements = difference (freeElements s) attemptedSet,
usedSubsets = attemptLabel : usedSubsets s
}
{-# INLINE step #-}
step :: Set set => State label set -> [State label set]
step s =
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 [usedSubsets s]
else step s >>= search
{-# INLINE partitions #-}
partitions :: Set set => [Assign label set] -> [[label]]
partitions = search . initState
data Tree label set = Leaf | Branch set [(label, Tree label set)]
deriving (Eq)
completeTree :: Choose set => State label set -> Tree label set
completeTree s =
if null (freeElements s)
then Leaf
else
uncurry Branch $
mapSnd (map (\asn -> (label asn, completeTree $ updateState asn s))) $
chooseMinimize (freeElements s) (availableSubsets s)
decisionTree :: Choose set => [Assign label set] -> Tree label set
decisionTree = completeTree . initState