-
Notifications
You must be signed in to change notification settings - Fork 0
/
stal.ml
225 lines (185 loc) · 10.2 KB
/
stal.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
(* ========================================================================= *)
(* Simple implementation of Stalmarck's algorithm. *)
(* *)
(* NB! This algorithm is patented for commercial use (not that a toy version *)
(* like this would actually be useful in practice). *)
(* ========================================================================= *)
(* ------------------------------------------------------------------------- *)
(* Triplet transformation, using functions defined earlier. *)
(* ------------------------------------------------------------------------- *)
let triplicate fm =
let fm' = nenf fm in
let n = Int 1 +/ overatoms (max_varindex "p_" ** pname) fm' (Int 0) in
let (p,defs,_) = maincnf (fm',undefined,n) in
p,map (snd ** snd) (graph defs);;
(* ------------------------------------------------------------------------- *)
(* Automatically generate triggering rules to save writing them out. *)
(* ------------------------------------------------------------------------- *)
let atom lit = if negative lit then negate lit else lit;;
let rec align (p,q) =
if atom p < atom q then align (q,p) else
if negative p then (negate p,negate q) else (p,q);;
let equate2 (p,q) eqv = equate (negate p,negate q) (equate (p,q) eqv);;
let rec irredundant rel eqs =
match eqs with
[] -> []
| (p,q)::oth ->
if canonize rel p = canonize rel q then irredundant rel oth
else insert (p,q) (irredundant (equate2 (p,q) rel) oth);;
let consequences (p,q as peq) fm eqs =
let follows(r,s) = tautology(Imp(And(Iff(p,q),fm),Iff(r,s))) in
irredundant (equate2 peq unequal) (filter follows eqs);;
let triggers fm =
let poslits = insert True (map (fun p -> Atom p) (atoms fm)) in
let lits = union poslits (map negate poslits) in
let pairs = allpairs (fun p q -> p,q) lits lits in
let npairs = filter (fun (p,q) -> atom p <> atom q) pairs in
let eqs = setify(map align npairs) in
let raw = map (fun p -> p,consequences p fm eqs) eqs in
filter (fun (p,c) -> c <> []) raw;;
(* ------------------------------------------------------------------------- *)
(* An example. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
triggers <<p <=> (q /\ r)>>;;
END_INTERACTIVE;;
(* ------------------------------------------------------------------------- *)
(* Precompute and instantiate triggers for standard triplets. *)
(* ------------------------------------------------------------------------- *)
let trigger =
let [trig_and; trig_or; trig_imp; trig_iff] = map triggers
[<<p <=> q /\ r>>; <<p <=> q \/ r>>;
<<p <=> (q ==> r)>>; <<p <=> (q <=> r)>>]
and p = <<p>> and q = <<q>> and r = <<r>>
and ddnegate fm = match fm with Not(Not p) -> p | _ -> fm in
let inst_fn [x;y;z] =
let subfn = fpf [P"p"; P"q"; P"r"] [x; y; z] in
ddnegate ** psubst subfn in
let inst2_fn i (p,q) = align(inst_fn i p,inst_fn i q) in
let instn_fn i (a,c) = inst2_fn i a,map (inst2_fn i) c in
let inst_trigger = map ** instn_fn in
function (Iff(x,And(y,z))) -> inst_trigger [x;y;z] trig_and
| (Iff(x,Or(y,z))) -> inst_trigger [x;y;z] trig_or
| (Iff(x,Imp(y,z))) -> inst_trigger [x;y;z] trig_imp
| (Iff(x,Iff(y,z))) -> inst_trigger [x;y;z] trig_iff;;
(* ------------------------------------------------------------------------- *)
(* Compute a function mapping each variable/true to relevant triggers. *)
(* ------------------------------------------------------------------------- *)
let relevance trigs =
let insert_relevant p trg f = (p |-> insert trg (tryapplyl f p)) f in
let insert_relevant2 ((p,q),_ as trg) f =
insert_relevant p trg (insert_relevant q trg f) in
itlist insert_relevant2 trigs undefined;;
(* ------------------------------------------------------------------------- *)
(* Merging of equiv classes and relevancies. *)
(* ------------------------------------------------------------------------- *)
let equatecons (p0,q0) (eqv,rfn as erf) =
let p = canonize eqv p0 and q = canonize eqv q0 in
if p = q then [],erf else
let p' = canonize eqv (negate p0) and q' = canonize eqv (negate q0) in
let eqv' = equate2(p,q) eqv
and sp_pos = tryapplyl rfn p and sp_neg = tryapplyl rfn p'
and sq_pos = tryapplyl rfn q and sq_neg = tryapplyl rfn q' in
let rfn' =
(canonize eqv' p |-> union sp_pos sq_pos)
((canonize eqv' p' |-> union sp_neg sq_neg) rfn) in
let nw = union (intersect sp_pos sq_pos) (intersect sp_neg sq_neg) in
itlist (union ** snd) nw [],(eqv',rfn');;
(* ------------------------------------------------------------------------- *)
(* Zero-saturation given an equivalence/relevance and new assignments. *)
(* ------------------------------------------------------------------------- *)
let rec zero_saturate erf assigs =
match assigs with
[] -> erf
| (p,q)::ts -> let news,erf' = equatecons (p,q) erf in
zero_saturate erf' (union ts news);;
(* ------------------------------------------------------------------------- *)
(* Zero-saturate then check for contradictoriness. *)
(* ------------------------------------------------------------------------- *)
let zero_saturate_and_check erf trigs =
let (eqv',rfn' as erf') = zero_saturate erf trigs in
let vars = filter positive (equated eqv') in
if exists (fun x -> canonize eqv' x = canonize eqv' (Not x)) vars
then snd(equatecons (True,Not True) erf') else erf';;
(* ------------------------------------------------------------------------- *)
(* Now we can quickly test for contradiction. *)
(* ------------------------------------------------------------------------- *)
let truefalse pfn = canonize pfn (Not True) = canonize pfn True;;
(* ------------------------------------------------------------------------- *)
(* Iterated equivalening over a set. *)
(* ------------------------------------------------------------------------- *)
let rec equateset s0 eqfn =
match s0 with
a::(b::s2 as s1) -> equateset s1 (snd(equatecons (a,b) eqfn))
| _ -> eqfn;;
(* ------------------------------------------------------------------------- *)
(* Intersection operation on equivalence classes and relevancies. *)
(* ------------------------------------------------------------------------- *)
let rec inter els (eq1,_ as erf1) (eq2,_ as erf2) rev1 rev2 erf =
match els with
[] -> erf
| x::xs ->
let b1 = canonize eq1 x and b2 = canonize eq2 x in
let s1 = apply rev1 b1 and s2 = apply rev2 b2 in
let s = intersect s1 s2 in
inter (subtract xs s) erf1 erf2 rev1 rev2 (equateset s erf);;
(* ------------------------------------------------------------------------- *)
(* Reverse the equivalence mappings. *)
(* ------------------------------------------------------------------------- *)
let reverseq domain eqv =
let al = map (fun x -> x,canonize eqv x) domain in
itlist (fun (y,x) f -> (x |-> insert y (tryapplyl f x)) f)
al undefined;;
(* ------------------------------------------------------------------------- *)
(* Special intersection taking contradictoriness into account. *)
(* ------------------------------------------------------------------------- *)
let stal_intersect (eq1,_ as erf1) (eq2,_ as erf2) erf =
if truefalse eq1 then erf2 else if truefalse eq2 then erf1 else
let dom1 = equated eq1 and dom2 = equated eq2 in
let comdom = intersect dom1 dom2 in
let rev1 = reverseq dom1 eq1 and rev2 = reverseq dom2 eq2 in
inter comdom erf1 erf2 rev1 rev2 erf;;
(* ------------------------------------------------------------------------- *)
(* General n-saturation for n >= 1 *)
(* ------------------------------------------------------------------------- *)
let rec saturate n erf assigs allvars =
let (eqv',_ as erf') = zero_saturate_and_check erf assigs in
if n = 0 or truefalse eqv' then erf' else
let (eqv'',_ as erf'') = splits n erf' allvars allvars in
if eqv'' = eqv' then erf'' else saturate n erf'' [] allvars
and splits n (eqv,_ as erf) allvars vars =
match vars with
[] -> erf
| p::ovars ->
if canonize eqv p <> p then splits n erf allvars ovars else
let erf0 = saturate (n - 1) erf [p,Not True] allvars
and erf1 = saturate (n - 1) erf [p,True] allvars in
let (eqv',_ as erf') = stal_intersect erf0 erf1 erf in
if truefalse eqv' then erf' else splits n erf' allvars ovars;;
(* ------------------------------------------------------------------------- *)
(* Saturate up to a limit. *)
(* ------------------------------------------------------------------------- *)
let rec saturate_upto vars n m trigs assigs =
if n > m then failwith("Not "^(string_of_int m)^"-easy") else
(print_string("*** Starting "^(string_of_int n)^"-saturation");
print_newline();
let (eqv,_) = saturate n (unequal,relevance trigs) assigs vars in
truefalse eqv or saturate_upto vars (n + 1) m trigs assigs);;
(* ------------------------------------------------------------------------- *)
(* Overall function. *)
(* ------------------------------------------------------------------------- *)
let stalmarck fm =
let include_trig (e,cqs) f = (e |-> union cqs (tryapplyl f e)) f in
let fm' = psimplify(Not fm) in
if fm' = False then true else if fm' = True then false else
let p,triplets = triplicate fm' in
let trigfn = itlist (itlist include_trig ** trigger)
triplets undefined
and vars = map (fun p -> Atom p) (unions(map atoms triplets)) in
saturate_upto vars 0 2 (graph trigfn) [p,True];;
(* ------------------------------------------------------------------------- *)
(* Examples. *)
(* ------------------------------------------------------------------------- *)
START_INTERACTIVE;;
time stalmarck (mk_adder_test 6 3);;
END_INTERACTIVE;;