twee-2.3: misc/MaxCover.hs
module MaxCover where
import SAT
import SAT.Optimize
import SAT.Unary hiding (modelValue)
import qualified SAT.Unary as Unary
import Data.List
import qualified Data.Map.Strict as Map
import Control.Monad
usort :: Ord a => [a] -> [a]
usort = map head . group . sort
maxCover :: (Ord label, Ord object) => Int -> [(label, [object])] -> IO [label]
maxCover limit xs = do
s <- newSolver
let
labels = map fst xs
objects = usort (concatMap snd xs)
labelLits <- sequence [newLit s | _ <- labels]
objectLits <- sequence [newLit s | _ <- objects]
let
labelMap = Map.fromList (zip labels labelLits)
labelInvMap = Map.fromList (zip labelLits labels)
objectMap = Map.fromList (zip objects objectLits)
find m x = Map.findWithDefault undefined x m
lits <-
maxCover_ s limit
[ (find labelMap label, map (find objectMap) objects)
| (label, objects) <- xs ]
return (map (find labelInvMap) lits)
maxCover_ :: Solver -> Int -> [(Lit, [Lit])] -> IO [Lit]
maxCover_ s limit xs = do
let
labels = map fst xs
objects = usort (concatMap snd xs)
occ = Map.fromListWith (++) [(obj, [label]) | (label, objs) <- xs, obj <- objs]
forM_ xs $ \(label, objs) -> do
forM_ objs $ \obj -> do
addClause s [neg label, obj]
forM_ objects $ \obj -> do
let labels = Map.findWithDefault undefined obj occ
addClause s (neg obj:labels)
numChosen <- count s labels
numCovered <- count s objects
-- Maximise #objects while respecting limit
addClause s [numChosen .<= limit]
True <- solveMaximize s [] numCovered
-- Now minimise #labels while preserving #objects
goal <- Unary.modelValue s numCovered
addClause s [numCovered .>= goal]
True <- solveMinimize s [] numChosen
filterM (modelValue s) labels