satchmo-2.9.7: Satchmo/Fourier_Motzkin.hs
{-# language TupleSections #-}
module Satchmo.Fourier_Motzkin where
import Satchmo.Data
import qualified Data.Map.Strict as M
import qualified Data.Set as S
import Control.Monad ( guard )
import Data.Monoid
import Data.List ( sortBy, nub )
import Data.Function (on)
import System.IO
type Solver = CNF -> IO (Maybe (M.Map Variable Bool))
fomo :: Solver
fomo cnf = do
print_info "fomo" cnf
( remove_satisfied $ trivial $ onesided $ eliminate fomo ) cnf
print_info msg cnf = do
hPutStrLn stderr $ unwords [ msg, show $ size cnf, "\n" ]
-- hPutStrLn stderr $ show cnf ++ "\n"
remove_satisfied cont cnf = do
print_info "remove_satisfied" cnf
let vars polar cl = S.fromList $ do
lit <- literals cl;
guard $ positive lit == polar
return $ variable lit
remaining = Satchmo.Data.filter
( \ cl -> disjoint ( vars True cl ) ( vars False cl ))
cnf
cont cnf
trivial :: Solver -> Solver
trivial cont cnf = do
print_info "trivial" cnf
if null $ clauses cnf
then return $ Just M.empty
else if clause [] `elem` clauses cnf
then return $ Nothing
else cont cnf
onesided :: Solver -> Solver
onesided cont cnf = do
print_info "onesided" cnf
let pos = occurrences True cnf
neg = occurrences False cnf
onlypos = M.keys $ M.difference pos neg
onlyneg = M.keys $ M.difference neg pos
assigned = M.fromList
$ map (,True) onlypos ++ map (,False) onlyneg
ks = M.keysSet assigned
others = Satchmo.Data.filter
( \ cl -> disjoint ks
$ S.fromList $ map variable $ literals cl)
cnf
hPutStrLn stderr $ unwords [ "assigned", show assigned , "\n" ]
later <- ( if size others < size cnf then fomo else cont ) others
return $ fmap ( M.union assigned ) later
disjoint s t = S.null $ S.intersection s t
eliminate :: Solver -> Solver
eliminate cont nf = do
print_info "eliminate" nf
let pos = occurrences True nf
neg = occurrences False nf
reductions = M.intersectionWith
( \ xs ys -> let lx = length xs
ly = length xs
in lx*ly - lx - ly
) pos neg
resolve v = cnf $ do
cp <- pos M.! v
let cpv = cp `without` v
cn <- neg M.! v
let cnv = cn `without` v
return $ cpv <> cnv
others v = Satchmo.Data.filter
( \ cl -> not $ elem v $ map variable $ literals cl )
nf
reconstruct v m = Prelude.or $ do
cp <- pos M.! v
return $ Prelude.not $ Prelude.or $ do
lit <- literals $ cp `without` v
let v = M.findWithDefault False ( variable lit ) m
return $ if positive lit then v else Prelude.not v
case sortBy (compare `on` snd) $ M.toList reductions of
(v,c): _ -> do
hPutStrLn stderr $ unwords [ "completely resolve", show v, "count", show c ]
later <- cont $ others v <> resolve v
return $ fmap
( \ m -> M.insert v (reconstruct v m) m)
later
-- | map each var to list of clauses where it occurs
occurrences :: Bool -> CNF -> M.Map Variable [Clause]
occurrences polarity =
flip Satchmo.Data.foldr M.empty $ \ cl ->
M.unionWith (++) $ M.fromList $ do
lit <- literals cl
guard $ positive lit == polarity
return ( variable lit, [cl] )