-
Notifications
You must be signed in to change notification settings - Fork 0
/
Solve.hs
151 lines (133 loc) · 4.91 KB
/
Solve.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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import Data.Maybe
import Data.List
import Data.Ord
import CSP
-- Forward checking
-- https://en.wikipedia.org/wiki/Look-ahead_(backtracking)
forwardcheck :: CSP -> Assignment -> Var -> (CSP, Bool)
forwardcheck csp a x = recforwardcheck csp a x ys
where
ys = allNeighboursOf x csp
recforwardcheck :: CSP -> Assignment -> Var -> [Var] -> (CSP, Bool)
recforwardcheck csp a x [] = (csp, True)
recforwardcheck csp a x (y:ys) =
if null domain then (csp, False)
else recforwardcheck (setDomain (y, domain) csp) a x ys
where
cs = commonConstraints csp x y
domain = filter (\i -> checkConstraints cs $ assign (y, i) a) $ getDomain y csp
-- Minimum Remaining Values (MRV)
getMRVVariable :: Assignment -> CSP -> Var
getMRVVariable a = fst . minimumBy (comparing (length . snd)) . domains
where
domains :: CSP -> Domains
domains = filter (not . isAssigned a . fst) . cspDomains
-- Least Constraining Value (LCV)
-- https://en.wikipedia.org/wiki/Min-conflicts_algorithm
{-
function LCVSort(csp, a, x) returns sorted domain of x
ys ← x neighbours
for each v in Dx do
assign x v
for each y in ys do
count Dy which satisfy the constraint between x and y
return sorted domain
function choices(csp, a, x, v) returns size of Dys if x assigned v
ys ← x neighbours
assign x v
sum for each y in ys do
count Dy which satisfy the constraint between x and y
return total
-}
lcvSort :: CSP -> Assignment -> Var -> [Int]
lcvSort csp assignment x = (reverse . sortBy (comparing choices) . flip getDomain csp) x
where
ys = filter (not . isAssigned assignment) $ allNeighboursOf x csp -- only check unassigned
choices :: Int -> Int
choices v = sum $ map checker ys
where
a = assign (x,v) assignment
checker :: Var -> Int
checker y = length domain
where
cs = commonConstraints csp x y
domain = filter (\i -> checkConstraints cs $ assign (y, i) a) $ getDomain y csp
-- Most Constraining Value (MCV)
mcvSort :: CSP -> Assignment -> Var -> [Int]
mcvSort csp assignment x = (sortBy (comparing choices) . flip getDomain csp) x
where
ys = filter (not . isAssigned assignment) $ allNeighboursOf x csp -- only check unassigned
choices :: Int -> Int
choices v = sum $ map checker ys
where
a = assign (x,v) assignment
checker :: Var -> Int
checker y = length domain
where
cs = commonConstraints csp x y
domain = filter (\i -> checkConstraints cs $ assign (y, i) a) $ getDomain y csp
{-
function REVISE(csp, Xi, Xj ) returns true iff we revise the domain of Xi
revised ← false
for each x in Di do
if no value y in Dj allows (x ,y) to satisfy the constraint between Xi and Xj then
delete x from Di
revised ← true
return revised
-}
revise :: CSP -> Var -> Var -> (CSP,Bool)
revise csp x y = foldl helper (csp, False) $ getDomain x csp
where
cs = commonConstraints csp x y
dy = getDomain y csp
helper :: (CSP,Bool) -> Int -> (CSP,Bool)
helper (csp, b) d =
if revised then (delDomainVal (x,d) csp, True)
else (csp, b)
where
revised = not $ any (checkConstraints cs) $ map (\v -> assign (y,v) a) dy
a = assign (x,d) []
{-
https://en.wikipedia.org/wiki/AC-3_algorithm
function AC-3(csp) returns false if an inconsistency is found and true otherwise
local variables: queue, a queue of arcs, initially all the arcs in csp
while queue is not empty do
(Xi, Xj) ← REMOVE-FIRST(queue)
if REVISE(csp, Xi, Xj ) then
if size of Di = 0 then return false
else
for each Xk in Xi.NEIGHBORS - {Xj} do
add (Xk, Xi) to queue
return true
-}
ac3Check :: CSP -> [(Var,Var)] -> (CSP,Bool)
ac3Check csp [] = (csp, True)
ac3Check csp ((i,j):s) =
if revised then
if null di then (csp', False)
else ac3Check csp' ns
else ac3Check csp s
where
(csp', revised) = revise csp i j
di = getDomain i csp'
ns = s ++ (map (\k -> (k, i)) $ filter (j/=) $ allNeighboursOf i csp)
solverRecursion :: CSP -> Assignment -> (Maybe Assignment, Int)
solverRecursion csp assignment =
if (isComplete csp assignment) then (Just assignment,0)
else findConsistentValue $ mcvSort acsp assignment var -- getDomain var acsp
where
var = getMRVVariable assignment csp
(acsp, passed) = ac3Check csp (map (\n -> (var, n)) $ allNeighboursOf var csp)
findConsistentValue :: Domain -> (Maybe Assignment, Int)
findConsistentValue [] = (Nothing,0)
findConsistentValue (val:vs) =
if passed then
if (isNothing result) then (ret,nodes+nodes'+1)
else (result,nodes+1)
else (ret,nodes'+1)
where assignment' = assign (var,val) assignment
(csp', passed) = forwardcheck acsp assignment' var
(result,nodes) = solverRecursion csp' assignment'
(ret,nodes') = findConsistentValue vs
solve :: CSP -> (Maybe Assignment,Int)
solve csp = solverRecursion csp []