-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathdecidable.ml
More file actions
351 lines (273 loc) · 13.1 KB
/
Copy pathdecidable.ml
File metadata and controls
351 lines (273 loc) · 13.1 KB
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
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
(* dummy commit *)
(* ========================================================================= *)
(* Special procedures for decidable subsets of first order logic. *)
(* *)
(* Copyright (c) 2003-2007, John Harrison. (See "LICENSE.txt" for details.) *)
(* ========================================================================= *)
(***
meson <<forall x. p(x)>>;;
tab <<forall x. p(x)>>;;
***)
(* ------------------------------------------------------------------------- *)
(* Resolution does actually terminate with failure in simple cases! *)
(* ------------------------------------------------------------------------- *)
(***
resolution <<forall x. p(x)>>;;
***)
(* ------------------------------------------------------------------------- *)
(* The Los example; see how Skolemized form has no non-nullary functions. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
let los =
<<(forall x y z. P(x,y) /\ P(y,z) ==> P(x,z)) /\
(forall x y z. Q(x,y) /\ Q(y,z) ==> Q(x,z)) /\
(forall x y. P(x,y) ==> P(y,x)) /\
(forall x y. P(x,y) \/ Q(x,y))
==> (forall x y. P(x,y)) \/ (forall x y. Q(x,y))>>;;
skolemize(Not los);;
(* ------------------------------------------------------------------------- *)
(* The old DP procedure works. *)
(* ------------------------------------------------------------------------- *)
davisputnam los;;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* However, we can just form all the ground instances. *)
(* ------------------------------------------------------------------------- *)
let aedecide fm =
let sfm = skolemize(Not fm) in
let fvs = fv sfm
and cnsts,funcs = partition (fun (_,ar) -> ar = 0) (functions sfm) in
if funcs <> [] then failwith "Not decidable" else
let consts = if cnsts = [] then ["c",0] else cnsts in
let cntms = map (fun (c,_) -> Fn(c,[])) consts in
let alltuples = groundtuples cntms [] 0 (length fvs) in
let cjs = simpcnf sfm in
let grounds = map
(fun tup -> image (image (subst (fpf fvs tup))) cjs) alltuples in
not(dpll(unions grounds));;
(* ------------------------------------------------------------------------- *)
(* In this case it's quicker. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
aedecide los;;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Show how we need to do PNF transformation with care. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
let fm = <<(forall x. p(x)) \/ (exists y. p(y))>>;;
pnf fm;;
(* ------------------------------------------------------------------------- *)
(* Also the group theory problem. *)
(* ------------------------------------------------------------------------- *)
aedecide
<<(forall x. P(1,x,x)) /\ (forall x. P(x,x,1)) /\
(forall u v w x y z.
P(x,y,u) /\ P(y,z,w) ==> (P(x,w,v) <=> P(u,z,v)))
==> forall a b c. P(a,b,c) ==> P(b,a,c)>>;;
aedecide
<<(forall x. P(x,x,1)) /\
(forall u v w x y z.
P(x,y,u) /\ P(y,z,w) ==> (P(x,w,v) <=> P(u,z,v)))
==> forall a b c. P(a,b,c) ==> P(b,a,c)>>;;
(* ------------------------------------------------------------------------- *)
(* A bigger example. *)
(* ------------------------------------------------------------------------- *)
aedecide
<<(exists x. P(x)) /\ (exists x. G(x))
==> ((forall x. P(x) ==> H(x)) /\ (forall x. G(x) ==> J(x)) <=>
(forall x y. P(x) /\ G(y) ==> H(x) /\ J(y)))>>;;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* The following, however, doesn't work with aedecide. *)
(* ------------------------------------------------------------------------- *)
(*** This is p18
aedecide <<exists y. forall x. P(y) ==> P(x)>>;;
davisputnam <<exists y. forall x. P(y) ==> P(x)>>;;
***)
(* ------------------------------------------------------------------------- *)
(* Simple-minded miniscoping procedure. *)
(* ------------------------------------------------------------------------- *)
let separate x cjs =
let yes,no = partition (mem x ** fv) cjs in
if yes = [] then list_conj no
else if no = [] then Exists(x,list_conj yes)
else And(Exists(x,list_conj yes),list_conj no);;
let rec pushquant x p =
if not (mem x (fv p)) then p else
let djs = purednf(nnf p) in
list_disj (map (separate x) djs);;
let rec miniscope fm =
match fm with
Not p -> Not(miniscope p)
| And(p,q) -> And(miniscope p,miniscope q)
| Or(p,q) -> Or(miniscope p,miniscope q)
| Forall(x,p) -> Not(pushquant x (Not(miniscope p)))
| Exists(x,p) -> pushquant x (miniscope p)
| _ -> fm;;
(* ------------------------------------------------------------------------- *)
(* Examples. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
miniscope(nnf <<exists y. forall x. P(y) ==> P(x)>>);;
let fm = miniscope(nnf
<<(forall x y. exists z. forall w. P(x) /\ Q(y) ==> R(z) /\ U(w))
==> (exists x y. P(x) /\ Q(y)) ==> (exists z. R(z))>>);;
pnf(nnf fm);;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Stronger version of "aedecide" similar to Wang's classic procedure. *)
(* ------------------------------------------------------------------------- *)
let wang fm = aedecide(miniscope(nnf(simplify fm)));;
(* ------------------------------------------------------------------------- *)
(* It works well on simple monadic formulas. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
wang
<<(forall x y. exists z. forall w. P(x) /\ Q(y) ==> R(z) /\ U(w))
==> (exists x y. P(x) /\ Q(y)) ==> (exists z. R(z))>>;;
(* ------------------------------------------------------------------------- *)
(* But not on this one! *)
(* ------------------------------------------------------------------------- *)
pnf(nnf(miniscope(nnf
<<((exists x. forall y. P(x) <=> P(y)) <=>
((exists x. Q(x)) <=> (forall y. Q(y)))) <=>
((exists x. forall y. Q(x) <=> Q(y)) <=>
((exists x. P(x)) <=> (forall y. P(y))))>>)));;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Checking classic Aristotelean syllogisms. *)
(* ------------------------------------------------------------------------- *)
let atom p x = Atom(R(p,[Var x]));;
let premiss_A (p,q) = Forall("x",Imp(atom p "x",atom q "x"))
and premiss_E (p,q) = Forall("x",Imp(atom p "x",Not(atom q "x")))
and premiss_I (p,q) = Exists("x",And(atom p "x",atom q "x"))
and premiss_O (p,q) = Exists("x",And(atom p "x",Not(atom q "x")));;
let anglicize_premiss fm =
match fm with
Forall(_,Imp(Atom(R(p,_)),Atom(R(q,_)))) -> "all "^p^" are "^q
| Forall(_,Imp(Atom(R(p,_)),Not(Atom(R(q,_))))) -> "no "^p^" are "^q
| Exists(_,And(Atom(R(p,_)),Atom(R(q,_)))) -> "some "^p^" are "^q
| Exists(_,And(Atom(R(p,_)),Not(Atom(R(q,_))))) ->
"some "^p^" are not "^q;;
let anglicize_syllogism (Imp(And(t1,t2),t3)) =
"If " ^ anglicize_premiss t1 ^ " and " ^ anglicize_premiss t2 ^
", then " ^ anglicize_premiss t3;;
let all_possible_syllogisms =
let sylltypes = [premiss_A; premiss_E; premiss_I; premiss_O] in
let prems1 = allpairs (fun x -> x) sylltypes ["M","P"; "P","M"]
and prems2 = allpairs (fun x -> x) sylltypes ["S","M"; "M","S"]
and prems3 = allpairs (fun x -> x) sylltypes ["S","P"] in
allpairs mk_imp (allpairs mk_and prems1 prems2) prems3;;
START_INTERACTIVE;;
let all_valid_syllogisms = filter aedecide all_possible_syllogisms;;
length all_valid_syllogisms;;
map anglicize_syllogism all_valid_syllogisms;;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* We can "fix" the traditional list by assuming nonemptiness. *)
(* ------------------------------------------------------------------------- *)
let all_possible_syllogisms' =
let p =
<<(exists x. P(x)) /\ (exists x. M(x)) /\ (exists x. S(x))>> in
map (fun t -> Imp(p,t)) all_possible_syllogisms;;
START_INTERACTIVE;;
let all_valid_syllogisms' = filter aedecide all_possible_syllogisms';;
length all_valid_syllogisms';;
map (anglicize_syllogism ** consequent) all_valid_syllogisms';;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Decide a formula on all models of size n. *)
(* ------------------------------------------------------------------------- *)
let rec alltuples n l =
if n = 0 then [[]] else
let tups = alltuples (n - 1) l in
allpairs (fun h t -> h::t) l tups;;
let allmappings dom ran =
itlist (fun p -> allpairs (valmod p) ran) dom [undef];;
let alldepmappings dom ran =
itlist (fun (p,n) -> allpairs (valmod p) (ran n)) dom [undef];;
let allfunctions dom n = allmappings (alltuples n dom) dom;;
let allpredicates dom n = allmappings (alltuples n dom) [false;true];;
let decide_finite n fm =
let funcs = functions fm and preds = predicates fm and dom = 1--n in
let fints = alldepmappings funcs (allfunctions dom)
and pints = alldepmappings preds (allpredicates dom) in
let interps = allpairs (fun f p -> dom,f,p) fints pints in
let fm' = generalize fm in
forall (fun md -> holds md undefined fm') interps;;
(* ------------------------------------------------------------------------- *)
(* Decision procedure in principle for formulas with finite model property. *)
(* ------------------------------------------------------------------------- *)
let limmeson n fm =
let cls = simpcnf(specialize(pnf fm)) in
let rules = itlist ((@) ** contrapositives) cls [] in
mexpand rules [] False (fun x -> x) (undefined,n,0);;
let limited_meson n fm =
let fm1 = askolemize(Not(generalize fm)) in
map (limmeson n ** list_conj) (simpdnf fm1);;
let decide_fmp fm =
let rec test n =
try limited_meson n fm; true with Failure _ ->
if decide_finite n fm then test (n + 1) else false in
test 1;;
START_INTERACTIVE;;
decide_fmp
<<(forall x y. R(x,y) \/ R(y,x)) ==> forall x. R(x,x)>>;;
decide_fmp
<<(forall x y z. R(x,y) /\ R(y,z) ==> R(x,z)) ==> forall x. R(x,x)>>;;
(*** This fails to terminate: has countermodels, but only infinite ones
decide_fmp
<<~((forall x. ~R(x,x)) /\
(forall x. exists z. R(x,z)) /\
(forall x y z. R(x,y) /\ R(y,z) ==> R(x,z)))>>;;
****)
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Semantic decision procedure for the monadic fragment. *)
(* ------------------------------------------------------------------------- *)
let decide_monadic fm =
let funcs = functions fm and preds = predicates fm in
let monadic,other = partition (fun (_,ar) -> ar = 1) preds in
if funcs <> [] or exists (fun (_,ar) -> ar > 1) other
then failwith "Not in the monadic subset" else
let n = funpow (length monadic) (( * ) 2) 1 in
decide_finite n fm;;
(* ------------------------------------------------------------------------- *)
(* Example. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
decide_monadic
<<((exists x. forall y. P(x) <=> P(y)) <=>
((exists x. Q(x)) <=> (forall y. Q(y)))) <=>
((exists x. forall y. Q(x) <=> Q(y)) <=>
((exists x. P(x)) <=> (forall y. P(y))))>>;;
(**** This is not feasible
decide_monadic
<<(forall x y. exists z. forall w. P(x) /\ Q(y) ==> R(z) /\ U(w))
==> (exists x y. P(x) /\ Q(y)) ==> (exists z. R(z))>>;;
****)
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Little auxiliary results for failure of finite model property. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
(*** Our claimed equivalences are indeed correct ***)
meson
<<(exists x y z. forall u.
R(x,x) \/ ~R(x,u) \/ (R(x,y) /\ R(y,z) /\ ~R(x,z))) <=>
~((forall x. ~R(x,x)) /\
(forall x. exists z. R(x,z)) /\
(forall x y z. R(x,y) /\ R(y,z) ==> R(x,z)))>>;;
meson
<<(exists x. forall y. exists z. R(x,x) \/ ~R(x,y) \/ (R(y,z) /\ ~R(x,z))) <=>
~((forall x. ~R(x,x)) /\
(forall x. exists y. R(x,y) /\ forall z. R(y,z) ==> R(x,z)))>>;;
(*** The second formula implies the first ***)
meson
<<~((forall x. ~R(x,x)) /\
(forall x. exists y. R(x,y) /\ forall z. R(y,z) ==> R(x,z)))
==> ~((forall x. ~R(x,x)) /\
(forall x. exists z. R(x,z)) /\
(forall x y z. R(x,y) /\ R(y,z) ==> R(x,z)))>>;;
END_INTERACTIVE;;