-
Notifications
You must be signed in to change notification settings - Fork 1
/
ta.ml
502 lines (433 loc) · 12.8 KB
/
ta.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
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
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
type atom = int
let tags = Hashtbl.create 64
let rev_tags = Hashtbl.create 64
let tag_id = ref 0
let atom_of_string x =
try Hashtbl.find tags x
with Not_found ->
let i = !tag_id in
incr tag_id;
Hashtbl.add tags x i;
Hashtbl.add rev_tags i x;
i
let string_of_atom x =
if x = -1 then "###"
else try Hashtbl.find rev_tags x
with Not_found -> assert false
type 'a fstsnd = Fst of 'a | Snd of 'a
type 'a descr = {
eps: bool;
trans: 'a Pt.Map.t;
def: 'a
}
type 'a nod = {
uid: int;
mutable undef: bool;
mutable descr: 'a
}
module rec Descr : Robdd.HashedOrdered with type t = Trans.t descr =
struct
type t = Trans.t descr
let equal n1 n2 =
(n1 == n2) ||
((n1.eps = n2.eps) &&
(Pt.Map.equal Trans.equal n1.trans n2.trans) &&
(Trans.equal n1.def n2.def))
let hash n =
(if n.eps then 0 else 1) +
17 * (Trans.hash n.def) + 65537 * (Pt.Map.hash Trans.hash n.trans)
let compare n1 n2 =
if n1.eps != n2.eps then if n1.eps then (-1) else 1
else let c = Trans.compare n1.def n2.def in
if c != 0 then c else Pt.Map.compare Trans.compare n1.trans n2.trans
end
and Trans : Robdd.S with type var = FstSnd.t = Robdd.Make(FstSnd)
and FstSnd : Robdd.HashedOrdered with type t = Descr.t nod fstsnd =
struct
type t = Descr.t nod fstsnd
let equal x y = match x,y with
| Fst n1, Fst n2 | Snd n1, Snd n2 -> n1 == n2
| _ -> false
let hash = function
| Fst n -> 2 * n.uid
| Snd n -> 2 * n.uid + 1
let compare x y = match x,y with
| Fst n1, Fst n2 -> n1.uid - n2.uid
| Snd n1, Snd n2 -> n1.uid - n2.uid
| Fst _, Snd _ -> -1
| Snd _, Fst _ -> 1
end
include Descr
let cur_id = ref 0
let typ eps tr def =
{ eps = eps;
def = def;
trans = Pt.Map.filter (fun _ d -> not (Trans.equal d def)) tr }
let any = typ true Pt.Map.empty Trans.one
let empty = typ false Pt.Map.empty Trans.zero
let eps = typ true Pt.Map.empty Trans.zero
let noneps = typ false Pt.Map.empty Trans.one
type node = Descr.t nod
let mk () =
incr cur_id;
{ uid = !cur_id; undef = true; descr = empty }
let def n t = n.descr <- t; n.undef <- false
let get t = assert(not t.undef); t.descr
let cons t = let n = mk () in def n t; n
let uid n = n.uid
let inter t1 t2 =
typ
(t1.eps && t2.eps)
(Pt.Map.combine Trans.(&&&) t1.def t2.def t1.trans t2.trans)
(Trans.(&&&) t1.def t2.def)
let diff t1 t2 =
typ
(t1.eps && not t2.eps)
(Pt.Map.combine Trans.(---) t1.def t2.def t1.trans t2.trans)
(Trans.(---) t1.def t2.def)
let union t1 t2 =
typ
(t1.eps || t2.eps)
(Pt.Map.combine Trans.(|||) t1.def t2.def t1.trans t2.trans)
(Trans.(|||) t1.def t2.def)
let neg t =
typ
(not t.eps)
(Pt.Map.map Trans.(~~~) t.trans)
(Trans.(~~~) t.def)
let is_trivially_empty t =
not t.eps && Trans.is_zero t.def && Pt.Map.is_empty t.trans
let is_trivially_any t =
t.eps && Trans.is_one t.def && Pt.Map.is_empty t.trans
type v = Eps | Elt of int * v * v
exception NotEmpty
type slot = { mutable status : status;
mutable notify : notify;
mutable active : bool;
mutable unknown : bool;
org: t;
}
and status = Empty | NEmpty of v | Maybe | Unknown
and notify = Nothing | Do of slot * (v -> unit) * notify
exception Undefined
let slot_empty =
{ org = empty; status = Empty; active = false; notify = Nothing;
unknown = false
}
let slot_not_empty v =
{ org = empty; status = NEmpty v; active = false; notify = Nothing;
unknown = false
}
let slot_eps = slot_not_empty Eps
let rec notify v = function
| Nothing -> ()
| Do (n,f,rem) ->
if n.status == Maybe then (try f v with NotEmpty -> ());
notify v rem
let set s v =
s.status <- NEmpty v;
notify v s.notify;
s.notify <- Nothing;
raise NotEmpty
let guard a f n = match a with
| { status = Empty } -> ()
| { status = Maybe } as s -> n.active <- true; s.notify <- Do (n,f,s.notify)
| { status = NEmpty v } -> f v
| { status = Unknown } -> assert false
module THash = Hashtbl.Make(Descr)
let memo = THash.create 8191
let marks = ref []
let rec slot (t : Descr.t) =
if t.eps then slot_eps
else if is_trivially_empty t then slot_empty
else
try THash.find memo t
with Not_found ->
let s = { org = t; status = Maybe; active = false; notify = Nothing;
unknown = false
} in
THash.add memo t s;
(try
check_times (Pt.Map.outdomain t.trans) s t.def;
Pt.Map.iter (fun i x -> check_times i s x) t.trans;
if s.active || s.unknown then marks := s :: !marks
else s.status <- Empty
with NotEmpty -> ());
s
and check_times i s t =
let rec aux v1 v2 accu1 accu2 t =
Trans.decompose
~pos:
(fun v t ->
match v with
| Fst (x : node) ->
if x.undef then s.unknown <- true
else let accu1 = inter accu1 (get x) in
guard (slot accu1) (fun v1 -> aux v1 v2 accu1 accu2 t) s
| Snd x ->
if x.undef then s.unknown <- true
else let accu2 = inter accu2 (get x) in
guard (slot accu2) (fun v2 -> aux v1 v2 accu1 accu2 t) s)
~neg:
(fun v t ->
match v with
| Fst x ->
if x.undef then s.unknown <- true
else let accu1 = diff accu1 (get x) in
guard (slot accu1) (fun v1 -> aux v1 v2 accu1 accu2 t) s
| Snd x ->
if x.undef then s.unknown <- true
else let accu2 = diff accu2 (get x) in
guard (slot accu2) (fun v2 -> aux v1 v2 accu1 accu2 t) s)
(fun () -> set s (Elt(i,v1,v2)))
t
in
aux Eps Eps any any t
let rec mark_unknown s =
s.status <- Unknown;
THash.remove memo s.org;
let rec aux = function
| Nothing -> ()
| Do (n,_,rem) -> if n.status == Maybe then mark_unknown n; aux rem
in
aux s.notify
let sample t =
let s = slot t in
List.iter
(fun s' ->
if s'.status == Maybe && s'.unknown then mark_unknown s')
!marks;
List.iter
(fun s' ->
if s'.status == Maybe then s'.status <- Empty; s'.notify <- Nothing)
!marks;
marks := [];
match s.status with
| Empty -> None
| NEmpty v -> Some v
| Unknown -> raise Undefined
| Maybe -> assert false
let is_empty t = sample t == None
let is_any t = is_empty (neg t)
let sample t =
match sample t with
| Some v -> v
| None -> raise Not_found
let non_empty t = not (is_empty t)
let subset t1 t2 = is_empty (diff t1 t2)
let disjoint t1 t2 = is_empty (inter t1 t2)
let is_equal t1 t2 = subset t1 t2 && subset t2 t1
let fst n =
if not (n.undef) && (is_trivially_any (get n)) then noneps
else typ false Pt.Map.empty (Trans.(!!!) (Fst n))
let snd n =
if not (n.undef) && (is_trivially_any (get n)) then noneps
else typ false Pt.Map.empty (Trans.(!!!) (Snd n))
let tag i =
typ false (Pt.Map.singleton i Trans.one) Trans.zero
let tag_in ts =
typ false (Pt.Map.constant ts Trans.one) Trans.zero
let tag_not_in ts =
typ false (Pt.Map.constant ts Trans.zero) Trans.one
let nottag i =
typ false (Pt.Map.singleton i Trans.zero) Trans.one
let get_trans t i =
try Pt.Map.find i t.trans
with Not_found -> t.def
let dnf_trans t =
let res = ref [] in
let rec aux accu1 accu2 t =
Trans.decompose
~pos:
(fun v t ->
match v with
| Fst x ->
let accu1 = inter accu1 (get x) in
if non_empty accu1 then aux accu1 accu2 t
| Snd x ->
let accu2 = inter accu2 (get x) in
if non_empty accu2 then aux accu1 accu2 t)
~neg:
(fun v t ->
match v with
| Fst x ->
let accu1 = diff accu1 (get x) in
if non_empty accu1 then aux accu1 accu2 t
| Snd x ->
let accu2 = diff accu2 (get x) in
if non_empty accu2 then aux accu1 accu2 t)
(fun () -> res := (accu1,accu2)::!res)
t
in
aux any any t;
!res
let dnf_neg_pair i t = dnf_trans (Trans.(~~~) (get_trans t i))
let dnf_neg_all t =
Pt.Map.domain t.trans,
dnf_trans (Trans.(~~~) t.def),
Pt.Map.fold (fun i x accu -> (i, dnf_trans (Trans.(~~~) x)) :: accu)
t.trans []
let rec is_in v t = match v with
| Eps -> t.eps
| Elt (i,v1,v2) ->
List.exists
(fun (t1,t2) -> is_in v1 t1 && is_in v2 t2)
(dnf_trans (get_trans t i))
let dump_tr l ppf = function
| Fst x -> l := x::!l; Format.fprintf ppf "L%i" x.uid
| Snd x -> l := x::!l; Format.fprintf ppf "R%i" x.uid
let print_tag ppf i =
try
let s = string_of_atom i in
Format.fprintf ppf "%s" s
with Not_found -> Format.fprintf ppf "%i" i
let rec print_tags ppf = function
| [i] -> print_tag ppf i
| i::l -> Format.fprintf ppf "%a|" print_tag i; print_tags ppf l
| [] -> assert false
let print ppf t =
let l = ref [] in
let p = ref [] in
let rec descr t =
if (try is_empty t with Undefined -> false) then Format.fprintf ppf "Empty"
else
let first = ref true in
let sep () = if !first then first := false else Format.fprintf ppf " | " in
if t.eps then (sep (); Format.fprintf ppf "()");
let h = ref Pt.Map.empty in
Pt.Map.iter
(fun i f ->
let id = Trans.uid f in
let l =
try Pervasives.snd (Pt.Map.find id !h)
with Not_found -> []
in
h := Pt.Map.add id (f,i::l) !h
) t.trans;
Pt.Map.iter
(fun _ (f,tags) ->
if not (Trans.is_zero f) then (
sep ();
Format.fprintf ppf "%a[%a]"
print_tags (List.sort Pervasives.compare tags)
(Trans.print_formula (dump_tr l)) (Trans.formula f)
)
)
!h;
if not (Trans.is_zero t.def) then (
sep ();
Format.fprintf ppf "*[%a]"
(Trans.print_formula (dump_tr l)) (Trans.formula t.def)
)
and loop () = match !l with [] -> () | t::rest ->
l := rest;
if List.memq t !p then ()
else (
p := t :: !p;
Format.fprintf ppf "%i:=" t.uid;
if t.undef then Format.fprintf ppf "UNDEF" else descr (get t);
Format.fprintf ppf "@."
);
loop ()
in
descr t;
Format.fprintf ppf "@.";
loop ()
let normalize_dnf l =
let rec add accu t1 t2 = function
| [] -> (t1,t2) :: accu
| ((s1,s2) as s)::rest ->
if disjoint s1 t1 then add (s::accu) t1 t2 rest
else
let t1' = inter t1 s1 in
let accu = (t1',union t2 s2) :: accu in
let s1' = diff s1 t1 in
let accu = if is_empty s1' then accu else (s1',s2) :: accu in
let t1 = diff t1 s1 in
if is_empty t1 then accu @ rest
else add accu t1 t2 rest
in
List.fold_left (fun accu (t1,t2) -> add [] t1 t2 accu) [] l
module Memo = Hashtbl.Make(Descr)
let normalize_memo = Memo.create 4096
let rec normalize t =
try Memo.find normalize_memo t
with Not_found ->
let n = mk () in
Memo.add normalize_memo t n;
def n (typ t.eps (Pt.Map.map norm_aux t.trans) (norm_aux t.def));
n
and norm_aux tr =
List.fold_left
(fun accu (t1,t2) ->
let t1 =
if is_any t1 then Trans.one else Trans.(!!!) (Fst (normalize t1))
and t2 =
if is_any t2 then Trans.one else Trans.(!!!) (Snd (normalize t2))
in
Trans.(|||) accu (Trans.(&&&) t1 t2)
)
Trans.zero
(dnf_trans tr)
let normalize t = (normalize t).descr
let normalize2_memo = Memo.create 4096
let rec normalize2 t =
try Memo.find normalize2_memo t
with Not_found ->
let n = mk () in
Memo.add normalize2_memo t n;
def n (typ t.eps (Pt.Map.map norm_aux t.trans) (norm_aux t.def));
n
and norm_aux tr =
List.fold_left
(fun accu (t1,t2) ->
let t1 =
if is_any t1 then Trans.one else Trans.(!!!) (Fst (normalize2 t1))
and t2 =
if is_any t2 then Trans.one else Trans.(!!!) (Snd (normalize2 t2))
in
Trans.(|||) accu (Trans.(&&&) t1 t2)
)
Trans.zero
(normalize_dnf (dnf_trans tr))
let normalize2 t = (normalize2 (normalize t)).descr
let rec print_v ppf = function
| Elt (i,v1,v2) ->
Format.fprintf ppf "%a[%a]%a"
print_tag i print_v_content v1 print_v_rest v2
| Eps -> Format.fprintf ppf "()"
and print_v_content ppf = function
| Eps -> ()
| x -> Format.fprintf ppf "%a" print_v x
and print_v_rest ppf = function
| Eps -> ()
| x -> Format.fprintf ppf ",%a" print_v x
let anyelt t1 t2 = inter (fst t1) (snd t2)
let elt i t1 t2 = inter (tag i) (anyelt t1 t2)
let rec singleton = function
| Eps -> eps
| Elt (i,v1,v2) -> elt i (cons (singleton v1)) (cons (singleton v2))
let is_defined t =
let seen = ref Pt.Set.empty in
let rec check_tr tr =
let id = Trans.uid tr in
if not (Pt.Set.mem id !seen) then
let () = seen := Pt.Set.add id !seen in
Trans.iter
(function Fst x | Snd x -> if x.undef then raise Exit; check_t (get x))
tr
and check_t x =
check_tr x.def;
Pt.Map.iter (fun _ tr -> check_tr tr) x.trans
in
try check_t t; true
with Exit -> false
let is_defined_node n =
not (n.undef) && (is_defined (get n))
let rec random_sample t =
let aux i x accu = List.map (fun (t1,t2) -> (i,t1,t2)) (dnf_trans x) @ accu in
let tr = Pt.Map.fold aux t.trans (aux (-1) t.def []) in
let l = List.length tr in
if t.eps && (l = 0 || Random.int 2 = 0) then Eps
else let (i,t1,t2) = List.nth tr (Random.int l) in
Elt (i,random_sample t1,random_sample t2)