-
Notifications
You must be signed in to change notification settings - Fork 0
/
DPLL.hs
133 lines (97 loc) · 5.08 KB
/
DPLL.hs
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
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
{- |
Module : <File name or $Header$ to be replaced automatically>
Description : An implementation of DPLL in Haskell.
Copyright : (c) Joshua T. Guerin, Ph.D.
License : <license>
Maintainer : jguerin@utm.edu
Stability : experimental
Portability : portable
<module description starting at first column>
-}
module DPLL where
import Data.List (sort, sortBy)
import Heuristics
import Common
cnf:: [[Int]]
cnf = [[16, 17, 30], [-17, 22, 30], [-17, -22, 30], [16, -30, 47], [16, -30, -47], [-16, -21, 31], [-16, -21, -31], [-16, 21, -28], [-13, 21, 28], [13, -16, 18], [13, -18, -38], [13, -18, -31], [31, 38, 44], [-8, 31, -44], [8, -12, -44], [8, 12, -27], [12, 27, 40], [-4, 27, -40], [12, 23, -40], [-3, 4, -23], [3, -23, -49], [3, -13, -49], [-23, -26, 49], [12, -34, 49], [-12, 26, -34], [19, 34, 36], [-19, 26, 36], [-30, 34, -36], [24, 34, -36], [-24, -36, 43], [6, 42, -43], [-24, 42, -43], [-5, -24, -42], [5, 20, -42], [5, -7, -20], [4, 7, 10], [-4, 10, -20], [7, -10, -41], [-10, 41, 46], [-33, 41, -46], [33, -37, -46], [32, 33, 37], [6, -32, 37], [-6, 25, -32], [-6, -25, -48], [-9, 28, 48], [-9, -25, -28], [19, -25, 48], [2, 9, -19], [-2, -19, 35], [-2, 22, -35], [-22, -35, 50], [-17, -35, -50], [-29, -35, -50], [-1, 29, -50], [1, 11, 29], [-11, 17, -45], [-11, 39, 45], [-26, 39, 45], [-3, -26, 45], [-11, 15, -39], [14, -15, -39], [14, -15, -45], [14, -15, -27], [-14, -15, 47], [17, 17, 40], [1, -29, -31], [-7, 32, 38], [-14, -33, -47], [-1, 2, -8], [35, 43, 44], [21, 21, 24], [20, 29, -48], [23, 35, -37], [2, 18, -33], [15, 25, -45], [9, 14, -38], [-5, 11, 50], [-3, -13, 46], [-13, -41, 43]]
-- | Generates a list of literals from cnf.
literals = filterDuplicates $ sort $
map (\x->if x>0 then x else (-x)) $ flatten cnf
propagatePurify :: [[Int]] -> ([[Int]], [Int])
{- ^
Wrapper for unitPropagate'.
Applies unit propagation until convergence.
-}
propagatePurify cnf = propagatePurify' cnf []
propagatePurify' :: [[Int]] -> [Int] -> ([[Int]], [Int])
-- ^ Repeatedly apply unit Propagation until convergence.
propagatePurify' cnf units =
if newUnits==[] && pures==[] then (cnf, units)
else propagatePurify' purified assignment
where (propagated, newUnits) = unitPropagate cnf
(purified, pures) = pureLiteralAssign propagated
assignment = filterDuplicates $ sortAssign (newUnits ++ pures ++ units)
unitPropagate :: [[Int]] -> ([[Int]], [Int])
-- ^ Apply unit propagation once to cnf.
unitPropagate cnf =
(reduceCNF units $ filter (not . clauseSat units) cnf, units)
where units = findUnits cnf
findUnits :: (Ord a, Num a) => [[a]] -> [a]
-- ^ Generates a lit of unit clauses.
findUnits cnf = sortAssign $ findUnits' cnf
findUnits' [] = []
findUnits' (x:xs)
| (length x) == 1 = (head x):findUnits' xs
| otherwise = findUnits' xs
pureLiteralAssign cnf = (applyAssignment pureList cnf, pureList)
where pureList = pureLiterals cnf
pureLiterals :: (Ord a, Num a) => [[a]] -> [a]
-- ^ Computes a list of pure literals from the cnf
pureLiterals cnf =
pureLiterals' positive negative
where candidates = sort $ flatten cnf
positive = filterDuplicates $ filter (\x->x>0) candidates
negative = filterDuplicates $ reverse $ filter (\x->x<0) candidates
pureLiterals' :: (Ord a, Num a) => [a] -> [a] -> [a]
{- ^
Helper function for pureLiterals
Parameters:
(x:xs) - A list of positive literals, ascending
(y:ys) - A list of negative literals, descending
Returns:
A list of pure literals (occurs positive or negative, not both).
-}
pureLiterals' [] [] = []
pureLiterals' (x:xs) [] = (x:xs)
pureLiterals' [] (y:ys) = (y:ys)
pureLiterals' (x:xs) (y:ys)
| x == (-y) = pureLiterals' xs ys
| x < (-y) = x:(pureLiterals' xs (y:ys))
| (-y) < x = y:(pureLiterals' (x:xs) ys)
contradiction :: Foldable t => [t a] -> Bool
-- ^ Checks for empty clauses (contradictions) in current theory.
contradiction cnf = foldr (||) False $ map (== 0) $ map length cnf
filterDuplicates :: Eq a => [a] -> [a]
-- ^ Filters out duplicate entries from a sorted list.
filterDuplicates [] = []
filterDuplicates [x] = [x]
filterDuplicates (x:xs) =
if x == (head xs) then filterDuplicates xs
else x:(filterDuplicates xs)
sortAssign list = sortBy (\x y -> if abs(x) < abs(y) then LT else GT) list
reduceCNF :: (Foldable t, Num a, Eq a) => t a -> [[a]] -> [[a]]
-- ^ Reduces opposite literals from assignment out of the CNF.
reduceCNF assignment cnf = map (reduce assignment) cnf
reduce :: (Foldable t, Num a, Eq a) => t a -> [a] -> [a]
-- ^ Reduce opposite literals from assignment out of clause.
reduce assignment clause = filter (\l ->(- l) `notElem` assignment) clause
applyAssignment :: [Int] -> [[Int]] -> [[Int]]
-- ^ Applies reduces CNF by assigned values.
applyAssignment assignment cnf = filter (not . clauseSat assignment) cnf
clauseSat :: [Int] -> [Int] -> Bool
-- ^ Returns True if assignment satisfies clause, False otherwise
clauseSat assignment clause =
foldr (||) False $ map (check assignment) clause
check :: [Int] -> Int -> Bool
-- ^ Checks whether the literal value is the same as the value in assignment
check assignment literal = literal `elem` assignment