feat(dimacs): add dimacs cnf parser and renderer
This commit is contained in:
1 parent
3104e31a5f
commit
34d591cbc3
1 file changed
+56
@@ -0,0 +1,56 @@
|
|||||||
|
module Sift.Dimacs
|
||||||
|
( parseDimacs
|
||||||
|
, renderDimacs
|
||||||
|
, renderModel
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Sift.Types
|
||||||
|
import Data.Char (isSpace)
|
||||||
|
import Data.List (sortOn)
|
||||||
|
import qualified Data.Map.Strict as Map
|
||||||
|
|
||||||
|
parseDimacs :: String -> Either String CNF
|
||||||
|
parseDimacs input = do
|
||||||
|
let toks = takeWhile (/= "%") (concatMap words (filter (not . isComment) (lines input)))
|
||||||
|
body <- case toks of
|
||||||
|
("p" : "cnf" : _ : _ : rest) -> Right rest
|
||||||
|
("p" : _) -> Left "malformed header, expected: p cnf <vars> <clauses>"
|
||||||
|
_ -> Right toks
|
||||||
|
ints <- traverse readInt body
|
||||||
|
Right (CNF (splitOnZero ints))
|
||||||
|
|
||||||
|
isComment :: String -> Bool
|
||||||
|
isComment line = case dropWhile isSpace line of
|
||||||
|
('c' : _) -> True
|
||||||
|
[] -> True
|
||||||
|
_ -> False
|
||||||
|
|
||||||
|
readInt :: String -> Either String Int
|
||||||
|
readInt s = case reads s of
|
||||||
|
[(n, "")] -> Right n
|
||||||
|
_ -> Left ("not an integer: " ++ show s)
|
||||||
|
|
||||||
|
splitOnZero :: [Int] -> [Clause]
|
||||||
|
splitOnZero [] = []
|
||||||
|
splitOnZero xs =
|
||||||
|
let (front, rest) = break (== 0) xs
|
||||||
|
clause = map litFromInt front
|
||||||
|
in case rest of
|
||||||
|
(0 : more) -> clause : splitOnZero more
|
||||||
|
_ -> [clause | not (null clause)]
|
||||||
|
|
||||||
|
renderDimacs :: CNF -> String
|
||||||
|
renderDimacs (CNF cs) = unlines (header : map renderClause cs)
|
||||||
|
where
|
||||||
|
maxVar = maximum (0 : map varId (concatMap varsOfClause cs))
|
||||||
|
header = "p cnf " ++ show maxVar ++ " " ++ show (length cs)
|
||||||
|
renderClause c = unwords (map (show . litToInt) c ++ ["0"])
|
||||||
|
|
||||||
|
renderModel :: CNF -> Assignment -> String
|
||||||
|
renderModel cnf model =
|
||||||
|
"v " ++ unwords (map (show . signedLit) orderedVars) ++ " 0"
|
||||||
|
where
|
||||||
|
orderedVars = sortOn varId (allVars cnf)
|
||||||
|
signedLit v =
|
||||||
|
let value = Map.findWithDefault True v model
|
||||||
|
in if value then varId v else negate (varId v)
|
||||||
Reference in new issue
Block a user