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
(* A data structure for binary relations on names *)
module M = Env.Make(String)
module S = Set.Make(String)
type t = S.t M.t
let empty : t = M.empty
let cardinal : t -> int = fun m ->
M.fold (fun _ s c -> S.cardinal s + c) m 0
let iter : (string -> string -> unit) -> t -> unit = fun f ->
M.iter (fun x -> S.iter (f x))
let diag : string list -> t =
List.fold_left (fun rel x -> M.add x (S.singleton x) rel) empty
let diag_set : S.t -> t = fun s ->
S.fold (fun x rel -> M.add x (S.singleton x) rel) s empty
let cross : S.t -> S.t -> t = fun s1 s2 ->
S.fold (fun x rel -> M.add x s2 rel) s1 empty
let lookup : string -> t -> S.t = fun k rel ->
match M.find_opt k rel with
| None -> S.empty
| Some s -> s
(* dom R = { x | (x,y) ∈ R } *)
let dom : t -> S.t = fun rel ->
M.fold (fun v s dom -> if S.is_empty s then dom else S.add v dom) rel S.empty
(* range R = { y | (x,y) ∈ R } *)
let range : t -> S.t = fun rel ->
M.fold (fun _ s ran -> S.union s ran) rel S.empty
(* remove_range R S = { (x,y) | (x,y) ∈ R ∧ y ∉ S } *)
let remove_range : S.t -> t -> t = fun s ->
M.map (fun s' -> S.diff s' s)
(* union R1 R2 = R1 ∪ R2 = { (x,y) | (x,y) ∈ R1 ∨ (x,y) ∈ R2 } *)
let union : t -> t -> t =
M.union (fun _ s1 s2 -> Some (S.union s1 s2))
let unions : t list -> t =
List.fold_left union empty
(* prod S1 S2 = S1 × S2 *)
let prod : S.t -> S.t -> t = fun s1 s2 ->
S.fold (fun x rel -> M.add x s2 rel) s1 empty
(* Just a utility function *)
let set_bind f s =
S.fold (fun y -> S.union (f y)) s S.empty
(* comp R1 R2 = R1 ∘ R2 = { (x,z) | (x,y) ∈ R1 ∧ (y,z) ∈ R2 } *)
let comp : t -> t -> t = fun rel1 rel2 ->
M.map (set_bind (fun y -> lookup y rel2)) rel1
(* We can use a relation R to represent its transitive closure R⁺,
and operations like dom, union, prod, comp work just fine.
Only removing needs special care:*)
(* remove_range_trans S R = R' where remove_range S R⁺ = R'⁺ *)
let remove_range_trans : S.t -> t -> t = fun s rel ->
M.map (set_bind (fun y -> if S.mem y s then S.diff (lookup y rel) s else S.singleton y)) rel
(* restricted_rtcl S R = { (x,z) | x ∈ S ∧ (x,z) ∈ R^* } *)
let restricted_rtcl : S.t -> t -> t = fun s rel ->
let rec go prev =
(* Add one iteration of R to the relation *)
let next = union prev (comp prev rel) in
(* Do we have a fixed point? *)
if cardinal prev = cardinal next
then prev
else go next
in go (diag_set s)