1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
------------------------------------------------------------------------------
--- This module defines an operation to solve a Boolean formula
--- with some SAT solver supporting the DIMACS format.
--- It also defines configuration for various solvers.
---
--- @author  Michael Hanus
--- @version September 2017
------------------------------------------------------------------------------

module Dimacs.Solver where

import IO
import IOExts

import Dimacs.Parser ( parse )
import Dimacs.Pretty ( showDimacs )
import Dimacs.Types

------------------------------------------------------------------------------
--- Type of solvers configuration with fields for the name of the executable
--- and command line flags.
data SolverConfig = Config
                      { executable  :: String
                      , flags       :: [String]
                      }

--- The configuration of the Z3 solver for DIMACS.
z3Dimacs :: SolverConfig
z3Dimacs = Config { executable = "z3"
                  , flags = ["-in", "-dimacs"]
                  }

--- The configuration of the lingeling solver.
lingeling :: SolverConfig
lingeling = Config { executable = "lingeling"
                   , flags = ["-q"]
                   }

------------------------------------------------------------------------------
--- Checks the satisfiability of a Boolean formula with a SAT solver
--- supporting DIMACS format.
--- A list associating the variable indices to Boolean values so that
--- the formula is satisfied is returned.
--- If the formula is unsatisfiable, the returned list is empty.
solveWithDimacs :: SolverConfig -> Boolean -> IO [(Int,Bool)]
solveWithDimacs scfg boolean = do
  let satcmd = unwords $ executable scfg : flags scfg
  (inH, outH, _) <- execCmd satcmd
  hPutStr inH $ showDimacs boolean
  hFlush inH
  hClose inH
  response <- hGetContents outH
  case parse response of
    Left  e -> error e
    Right b -> return (boolVars2AssocList b)

--- Translates a list of Boolean variables into a list associating
--- the variable indices to Boolean values.
boolVars2AssocList :: [Boolean] -> [(Int,Bool)]
boolVars2AssocList = map bvar2assoc
 where
  bvar2assoc bv = case bv of
    Var i       -> (i,True)
    Not (Var i) -> (i,False)
    _           -> error $ "boolVars2AssocList: not a variable: " ++ show bv

------------------------------------------------------------------------------