Source file Msat_tseitin.ml
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
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
module type Arg = Tseitin_intf.Arg
module type S = Tseitin_intf.S
module Make (F : Tseitin_intf.Arg) = struct
exception Empty_Or
type combinator = And | Or | Imp | Not
type atom = F.t
type t =
| True
| Lit of atom
| Comb of combinator * t list
let rec pp fmt phi =
match phi with
| True -> Format.fprintf fmt "true"
| Lit a -> F.pp fmt a
| Comb (Not, [f]) ->
Format.fprintf fmt "not (%a)" pp f
| Comb (And, l) -> Format.fprintf fmt "(%a)" (pp_list "and") l
| Comb (Or, l) -> Format.fprintf fmt "(%a)" (pp_list "or") l
| Comb (Imp, [f1; f2]) ->
Format.fprintf fmt "(%a => %a)" pp f1 pp f2
| _ -> assert false
and pp_list sep fmt = function
| [] -> ()
| [f] -> pp fmt f
| f::l -> Format.fprintf fmt "%a %s %a" pp f sep (pp_list sep) l
let make comb l = Comb (comb, l)
let make_atom p = Lit p
let f_true = True
let f_false = Comb(Not, [True])
let rec flatten comb acc = function
| [] -> acc
| (Comb (c, l)) :: r when c = comb ->
flatten comb (List.rev_append l acc) r
| a :: r ->
flatten comb (a :: acc) r
let rec opt_rev_map f acc = function
| [] -> acc
| a :: r -> begin match f a with
| None -> opt_rev_map f acc r
| Some b -> opt_rev_map f (b :: acc) r
end
let remove_true l =
let aux = function
| True -> None
| f -> Some f
in
opt_rev_map aux [] l
let remove_false l =
let aux = function
| Comb(Not, [True]) -> None
| f -> Some f
in
opt_rev_map aux [] l
let make_not f = make Not [f]
let make_and l =
let l' = remove_true (flatten And [] l) in
if List.exists ((=) f_false) l' then
f_false
else
make And l'
let make_or l =
let l' = remove_false (flatten Or [] l) in
if List.exists ((=) f_true) l' then
f_true
else match l' with
| [] -> raise Empty_Or
| [a] -> a
| _ -> Comb (Or, l')
let make_imply f1 f2 = make Imp [f1; f2]
let make_equiv f1 f2 = make_and [ make_imply f1 f2; make_imply f2 f1]
let make_xor f1 f2 = make_or [ make_and [ make_not f1; f2 ];
make_and [ f1; make_not f2 ] ]
let (%%) f g x = f (g x)
let rec sform f k = match f with
| True | Comb (Not, [True]) -> k f
| Comb (Not, [Lit a]) -> k (Lit (F.neg a))
| Comb (Not, [Comb (Not, [f])]) -> sform f k
| Comb (Not, [Comb (Or, l)]) -> sform_list_not [] l (k %% make_and)
| Comb (Not, [Comb (And, l)]) -> sform_list_not [] l (k %% make_or)
| Comb (And, l) -> sform_list [] l (k %% make_and)
| Comb (Or, l) -> sform_list [] l (k %% make_or)
| Comb (Imp, [f1; f2]) ->
sform (make_not f1) (fun f1' -> sform f2 (fun f2' -> k (make_or [f1'; f2'])))
| Comb (Not, [Comb (Imp, [f1; f2])]) ->
sform f1 (fun f1' -> sform (make_not f2) (fun f2' -> k (make_and [f1';f2'])))
| Comb ((Imp | Not), _) -> assert false
| Lit _ -> k f
and sform_list acc l k = match l with
| [] -> k acc
| f :: tail ->
sform f (fun f' -> sform_list (f'::acc) tail k)
and sform_list_not acc l k = match l with
| [] -> k acc
| f :: tail ->
sform (make_not f) (fun f' -> sform_list_not (f'::acc) tail k)
let ( @@ ) l1 l2 = List.rev_append l1 l2
let mk_proxy = F.fresh
let acc_or = ref []
let acc_and = ref []
let rec cnf f = match f with
| Lit a -> None, [a]
| Comb (Not, [Lit a]) -> None, [F.neg a]
| Comb (And, l) ->
List.fold_left
(fun (_, acc) f ->
match cnf f with
| _, [] -> assert false
| _cmb, [a] -> Some And, a :: acc
| Some And, l ->
Some And, l @@ acc
| Some Or, l ->
let proxy = mk_proxy () in
acc_or := (proxy, l) :: !acc_or;
Some And, proxy :: acc
| None, l -> Some And, l @@ acc
| _ -> assert false
) (None, []) l
| Comb (Or, l) ->
List.fold_left
(fun (_, acc) f ->
match cnf f with
| _, [] -> assert false
| _cmb, [a] -> Some Or, a :: acc
| Some Or, l ->
Some Or, l @@ acc
| Some And, l ->
let proxy = mk_proxy () in
acc_and := (proxy, l) :: !acc_and;
Some Or, proxy :: acc
| None, l -> Some Or, l @@ acc
| _ -> assert false
) (None, []) l
| _ -> assert false
let cnf f =
let acc = match f with
| True -> []
| Comb(Not, [True]) -> [[]]
| Comb (And, l) -> List.rev_map (fun f -> snd(cnf f)) l
| _ -> [snd (cnf f)]
in
let proxies = ref [] in
let acc =
List.fold_left
(fun acc (p,l) ->
proxies := p :: !proxies;
let np = F.neg p in
let cl, acc =
List.fold_left
(fun (cl,acc) a -> (F.neg a :: cl), [np; a] :: acc)
([p],acc) l in
cl :: acc
) acc !acc_and
in
let acc =
List.fold_left
(fun acc (p,l) ->
proxies := p :: !proxies;
let acc = List.fold_left (fun acc a -> [p; F.neg a]::acc)
acc l in
(F.neg p :: l) :: acc
) acc !acc_or
in
acc
let make_cnf f =
acc_or := [];
acc_and := [];
cnf (sform f (fun f' -> f'))
end