···11+22+(* Word Graph
33+ (example taken from The Stanford GraphBase)
44+55+ Given a number of letters n and a file containing words (one per line),
66+ this program builds the undirected graph where
77+ - vertices are words of length n;
88+ - two words are connected with an edge if they differ by exactly one letter.
99+1010+ Then the program computes and prints the components.
1111+1212+ Finally, it repeatedly queries a word from the user and displays
1313+ its component.
1414+*)
1515+1616+open Format
1717+open Graph
1818+1919+module S = struct
2020+ type t = string
2121+ let compare = compare
2222+ let hash = Hashtbl.hash
2323+ let equal = (=)
2424+end
2525+module H = Hashtbl.Make(S)
2626+2727+module G = Imperative.Graph.Abstract(S)
2828+let g = G.create ()
2929+3030+let words : G.V.t H.t = H.create 16
3131+3232+let add_word w =
3333+ let v = G.V.create w in H.add words w v; G.add_vertex g v
3434+3535+let rec read_words n c =
3636+ match input_line c with
3737+ | s -> if String.length s = n then add_word s; read_words n c
3838+ | exception End_of_file -> ()
3939+4040+let () =
4141+ try match Sys.argv with [| _; n; f |] ->
4242+ let n = int_of_string n in
4343+ let c = open_in f in
4444+ read_words n c;
4545+ close_in c;
4646+ | _ -> raise Exit
4747+ with _ -> eprintf "%s <int> <file>@." Sys.argv.(0); exit 1
4848+4949+let () = printf "%d words@." (G.nb_vertex g)
5050+5151+let diff1 s1 s2 =
5252+ let n = String.length s1 in
5353+ assert (String.length s2 = n);
5454+ let rec scan d i =
5555+ i = n && d = 1 ||
5656+ i < n && if s1.[i] = s2.[i] then scan d (i+1) else d = 0 && scan 1 (i+1) in
5757+ scan 0 0
5858+5959+let () =
6060+ G.iter_vertex (fun v1 ->
6161+ G.iter_vertex (fun v2 ->
6262+ if diff1 (G.V.label v1) (G.V.label v2) then G.add_edge g v1 v2
6363+ ) g) g
6464+6565+let () = printf "%d edges@." (G.nb_edges g)
6666+6767+module C = Components.Undirected(G)
6868+let comp = C.components_array g
6969+7070+let histogram a =
7171+ let h = Hashtbl.create (Array.length a) in
7272+ let incr v =
7373+ Hashtbl.replace h v (1 + try Hashtbl.find h v with Not_found -> 0) in
7474+ Array.iter incr a;
7575+ let l = Hashtbl.fold (fun v n acc -> (v, n) :: acc) h [] in
7676+ List.sort (fun (v1, _) (v2, _) -> compare v1 v2) l
7777+7878+let () =
7979+ printf "%d components@." (Array.length comp);
8080+ Array.sort (fun l1 l2 -> Stdlib.compare (List.length l1) (List.length l2))
8181+ comp;
8282+ let print1 v = printf "@ %s" (G.V.label v) in
8383+ let print c =
8484+ printf "@[<hov 2>%d:" (List.length c); List.iter print1 c; printf "@]@." in
8585+ Array.iter print comp;
8686+ let hist = histogram (Array.map List.length comp) in
8787+ List.iter (fun (v, n) -> printf "%d component(s) of size %d@." n v) hist
8888+8989+module D = Traverse.Dfs(G)
9090+9191+let () =
9292+ while true do
9393+ printf "start: @?";
9494+ let s = read_line () in
9595+ try
9696+ let v = H.find words s in
9797+ printf "@[<hov 2>component:";
9898+ let m = ref 0 in
9999+ let visit v = printf "@ %s" (G.V.label v); incr m in
100100+ D.prefix_component visit g v;
101101+ printf "@]@.";
102102+ printf "%d word(s)@." !m
103103+ with Not_found ->
104104+ printf "not a vertex@."
105105+ done