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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
|
module Dimacs.FromFD where
import Integer as I
import XFD.FD
import XFD.State
import Dimacs.Types
import Dimacs.Build
ilog2 :: Int -> Int
ilog2 n | n>0 = if n<2 then 0 else 1 + ilog2 (n `div` 2)
numBits :: Int -> Int
numBits = (2+) . ilog2
numBitsFor :: Int -> Int -> Int
numBitsFor l u = numBits $ max ((I.abs l)-1) (I.abs u)
dTrue, dFalse :: Boolean
dTrue = va 1
dFalse = nv 1
type DimacsState = (Int, [(String, [Boolean])])
type ConvertState a = State DimacsState a
convertFDVars :: [FDExpr] -> ConvertState ()
convertFDVars fdvs = (mapS_ convertFDVar $ reverse fdvs)
convertFDVar :: FDExpr -> ConvertState ()
convertFDVar var = case var of
(FDVar n l u _) -> modifyS addVar
where
addVar :: DimacsState -> DimacsState
addVar (i, vs) = (i+neededBits, (n, map va [(i+1)..(i+neededBits)]):vs)
neededBits :: Int
neededBits = numBitsFor l u
_ -> error "should not happen"
type SimplificationState a = State [Boolean] a
convertSimplifications :: [Simplification] -> Int -> ConvertState Boolean
convertSimplifications simps i s@(_, lVars) =
let bsimps = evalState (mapS (convertSimplification lVars) simps) (map va [i ..])
in (foldr (./\) dTrue bsimps, s)
convertSimplification :: [(String, [Boolean])] -> Simplification -> SimplificationState Boolean
convertSimplification lVars simp bools = (arithmetic simp lVars) bools
convertFDConstr :: FDConstr -> ConvertState Boolean
convertFDConstr constr = case constr of
FDTrue -> returnS $ dTrue
FDFalse -> returnS $ dFalse
FDRelCon rel e1 e2 -> (convertFDRel rel) e1 e2
FDAnd c1 c2 -> liftS2 (./\) (convertFDConstr c1) (convertFDConstr c2)
FDOr c1 c2 -> liftS2 (.\/) (convertFDConstr c1) (convertFDConstr c2)
FDNot c -> liftS no $ convertFDConstr c
_ -> error $ "can't convert " ++ show constr
convertFDRel :: FDRel -> FDExpr -> FDExpr -> ConvertState Boolean
convertFDRel rel = case rel of
Equ -> convertEqual
_ -> error "not yet implemented"
convertEqual :: FDExpr -> FDExpr -> ConvertState Boolean
convertEqual e1 e2 = case (e1, e2) of
(FDInt i, FDInt j) -> if i == j then returnS (dTrue) else returnS (dFalse)
_ -> booleanEqual e1 e2
booleanEqual :: FDExpr -> FDExpr -> ConvertState Boolean
booleanEqual e1 e2 = case (e1, e2) of
(FDInt i, FDVar n _ _ _) -> getS `bindS` \(_, vars) ->
returnS $ setEq (toBits i)
(lookupVar n vars)
(FDVar _ _ _ _, FDInt _) -> booleanEqual e2 e1
(FDVar n _ _ _, FDVar m _ _ _) -> getS `bindS` \(_, vars) ->
returnS $ setEq (lookupVar m vars)
(lookupVar n vars)
_ -> error "should not happen"
setEq :: [Boolean] -> [Boolean] -> Boolean
setEq xss yss = case (xss, yss) of
([x], [y]) -> eqVars x y
(xs@(_:_), [y]) -> foldr1 (./\) $ zipWith (eqVars) xs (replicate (length xs) y)
([y], xs@(_:_)) -> setEq xs [y]
((x:xs), (y:ys)) -> eqVars x y ./\ setEq xs ys
_ -> error "empty lists should not happen"
where
eqVars :: Boolean -> Boolean -> Boolean
eqVars x y = x ./\ y .\/ no x ./\ no y
toBits :: Int -> [Boolean]
toBits i
| i < 0 = negative (toBits (-i)) True
| otherwise = toBits' i ++ [dFalse]
where
toBits' :: Int -> [Boolean]
toBits' j = case j of
0 -> [dFalse]
1 -> [dTrue]
_ -> let b = if j `mod` 2 == 1 then dTrue else dFalse
in b : toBits' (j `div` 2)
negative [] _ = []
negative (x:xs) b = case (x, b) of
(Var _, True) -> dTrue : negative xs False
(Var _, False) -> dFalse : negative xs False
(Not (Var _), True) -> dFalse : negative xs True
(Not (Var _), False) -> dTrue : negative xs False
_ -> error "XFD.Dimacs.toBits, in where: negative only takes Var"
lookupVar :: String -> [(String, [Boolean])] -> [Boolean]
lookupVar v vs = maybe [] id (lookup v vs)
convert :: ConvertState a -> (a, DimacsState)
convert state = runState state (1, [])
fullAdder :: Boolean -> Boolean -> Boolean -> Boolean -> Boolean -> Boolean
fullAdder a b cin s cout = res ./\ carry
where
res = (s .\/ a .\/ b .\/ no cin)
./\ (s .\/ a .\/ no b .\/ cin)
./\ (s .\/ no a .\/ b .\/ cin)
./\ (s .\/ no a .\/ no b .\/ no cin)
./\ (no s .\/ a .\/ b .\/ cin)
./\ (no s .\/ a .\/ no b .\/ no cin)
./\ (no s .\/ no a .\/ b .\/ no cin)
./\ (no s .\/ no a .\/ no b .\/ cin)
carry = (cout .\/ a .\/ no b .\/ no cin)
./\ (cout .\/ no a .\/ b .\/ no cin)
./\ (cout .\/ no a .\/ no b .\/ cin)
./\ (cout .\/ no a .\/ no b .\/ no cin)
./\ (no cout .\/ a .\/ b .\/ cin)
./\ (no cout .\/ a .\/ b .\/ no cin)
./\ (no cout .\/ a .\/ no b .\/ cin)
./\ (no cout .\/ no a .\/ b .\/ cin)
arithmetic :: Simplification -> [(String, [Boolean])] -> [Boolean] -> (Boolean, [Boolean])
arithmetic (SimplifyAdd z x y) vars = adder z x y vars
arithmetic (SimplifySub _ _ _) _ = error "XFD.Dimacs.arithmetic: Subtractions not yet supported"
arithmetic (SimplifyMul _ _ _) _ = error "XFD.Dimacs.arithmetic: Multiplications not yet supported"
adder :: FDExpr -> FDExpr -> FDExpr -> [(String, [Boolean])] -> [Boolean] -> (Boolean, [Boolean])
adder vz vx vy lVars vars = case (vz,vx,vy) of
(FDVar zn _ _ _, FDVar xn _ _ _, FDVar yn _ _ _) -> adder' zn xn yn
_ -> error $ "XFD.Dimacs.adder: found non FDVar in " ++ show (vz,vx,vy)
where
adder' :: String -> String -> String -> (Boolean, [Boolean])
adder' zn xn yn =
let z = lookupVar zn lVars
(x,y) = padd (lookupVar xn lVars) (lookupVar yn lVars)
lz = (length z)
c = (take lz vars)
in (add z x y c dFalse, drop lz vars)
add :: [Boolean] -> [Boolean] -> [Boolean] -> [Boolean] -> Boolean -> Boolean
add zss xss yss c cin = case (zss, xss, yss) of
([zm,zn], [xn], [yn]) -> fullAdder xn yn cin zn zm
([zn], [xn], [yn]) -> fullAdder xn yn cin zn (head c)
((z:zs@(_:_)), (x:xs@(_:_)), (y:ys@(_:_))) -> fullAdder x y cin z (head c)./\ add zs xs ys (tail c) (head c)
_ -> error $ "XFD.Dimacs.adder where add: lists mismatched" ++ show (zss,xss,yss)
padd :: [Boolean] -> [Boolean] -> ([Boolean], [Boolean])
padd x y | lx == ly = (x, y)
| lx < ly = (padd' x, y)
| lx > ly = (x, padd' y)
where
lx = length x
ly = length y
ld = I.abs (lx - ly)
padd' [] = []
padd' [v] = replicate ld v
padd' (v:vs@(_:_)) = v : padd' vs
data Simplification = SimplifyAdd FDExpr FDExpr FDExpr
| SimplifySub FDExpr FDExpr FDExpr
| SimplifyMul FDExpr FDExpr FDExpr
type Simplified a = ([Simplification], Int, a)
simplifyConstr :: FDConstr -> Simplified FDConstr
simplifyConstr constr = simpleC ([], 0, constr)
where
simpleC :: Simplified FDConstr -> Simplified FDConstr
simpleC p = case p of
(_, _, FDTrue) -> p
(_, _, FDFalse) -> p
(s, i, FDNot c) -> let (s', i', c') = simpleC (s, i, c) in (s', i', notC c')
(s, i, FDAnd a b) -> let (s1, i1, a') = simpleC (s, i, a)
(s2, i2, b') = simpleC (s1, i1, b)
in (s2, i2, a' /\ b')
(s, i, FDOr a b) -> let (s1, i1, a') = simpleC (s, i, a)
(s2, i2, b') = simpleC (s1, i1, b)
in (s2, i2, a' \/ b')
(s, i, FDRelCon r a b) -> let (s1, i1, a') = simpleE (s, i, a)
(s2, i2, b') = simpleE (s1, i1, b)
in (s2, i2, FDRelCon r a' b')
(_, _, c) -> error $ "XFD.Dimacs.simplifyConstr where simpleC: not yet implemented for " ++ show c
simpleE :: Simplified FDExpr -> Simplified FDExpr
simpleE p = case p of
(s, n, FDBinExp op a b) -> case (a,b) of
(FDInt i, FDInt j) -> let (o,_) = oc op in (s, n, fd (i `o` j))
_ -> let (s1, n1, a') = simpleE (s, n, a)
(s2, n2, b') = simpleE (s1, n1, b)
(o,c) = oc op
ab@(FDVar _ l u _) = newDomainVar o a' b' (length s2)
n3 = (numBitsFor l u)
s' = c ab a' b'
in (s':s2, n2+n3, ab)
(_, _, FDVar _ _ _ _) -> p
(_, _, FDInt _) -> p
oc :: FDOp -> ((Int -> Int -> Int), (FDExpr -> FDExpr -> FDExpr -> Simplification))
oc Plus = ((+), SimplifyAdd)
oc Minus = ((-), SimplifySub)
oc Times = ((*), SimplifyMul)
newDomainVar :: (Int -> Int -> Int) -> FDExpr -> FDExpr -> Int -> FDExpr
newDomainVar op a b n = (head . take 1) $ case (a, b) of
(FDVar an al au _, FDVar bn bl bu _) -> domainWPrefix (prefix an bn) (al `op` bl) (au `op` bu)
(FDVar an al au _, FDInt i) -> domainWPrefix (prefix an (show i)) (al `op` i) (au `op` i)
(FDInt i, FDVar an al au _) -> domainWPrefix (prefix (show i) an) (al `op` i) (au `op` i)
_ -> error "XFD.Dimacs.simplifyConstr where newDomainVar: only FDVar or FDInt"
where
prefix x y = "sVar_"++(show n)++"_"++x++y
extractSolution :: [String] -> [(String, [Boolean])] -> [Boolean] -> [FDExpr]
extractSolution [] _ _ = []
extractSolution (n:ns) lVars sol = case (lookupVar n lVars, sol) of
([], _) -> extractSolution ns lVars sol
(_, []) -> []
(vars, _) -> (FDVar n _ _ (val vars sol)) : extractSolution ns lVars sol
where
val l s = getVal ((num (head l))-1) (length l) s
num var = case var of
(Var i) -> i
_ -> error "should not happen"
getVal l u s = binVal (take u $ drop l s)
binVal :: [Boolean] -> Int
binVal [] = 0
binVal bits@(_:_) = binVal' bits 1
where
binVal' [] _ = 0
binVal' (v:vs) val = case (v, null vs) of
(Var _, False) -> val + (binVal' vs (val*2))
(Var _, True) -> (-val)
(Not (Var _), _) -> binVal' vs (val*2)
_ -> error "XFD.Dimacs.binVal, in where: binVal' only takes Vars"
|