(* 0: 7 1: 29 2: 120 3: > 319 4: ??? *) type t = M | I | C type w = t list type eqclass = w list type dir = Le | Ge let rules = [ [I], Le, []; [C], Ge, []; [I;I], Ge, [I]; [C;C], Le, [C]; [I], Le, [I]; [I], Ge, [I]; [C], Le, [C]; [C], Ge, [C]; [C;M], Le, [M;I]; [C;M;I], Le, [M;I]; (* ??? *) [I;M], Le, [M;C]; [I;M;C], Ge, [I;M]; (* ??? *) [M;M;M], Ge, [M]; [M;M], Ge, []; [M], Le, [M]; [M], Ge, [M]; (* classical [M;M], Le, []; [C;M], Ge, [M;I]; *) ] ;; let swap = function Le -> Ge | Ge -> Le;; let rec new_dir dir = function [] -> dir | M::tl -> new_dir (swap dir) tl | (C|I)::tl -> new_dir dir tl ;; let string_of_w w = String.concat "" (List.map (function I -> "i" | C -> "c" | M -> "-") w) ;; exception NoMatch;; let (@@) l1 ll2 = List.map (function l2 -> l1 @ l2) ll2;; let uniq l = let rec aux acc = function | [] -> acc | h::[] -> h::acc | h1::h2::tl when h1=h2 -> aux (h2::acc) tl | h1::tl (* when h1 <> h2 *) -> aux (h1::acc) tl in List.rev (aux [] (List.sort compare l)) ;; let rec apply_rule_at_beginning (lhs,dir',rhs) (w,dir) = if dir <> dir' then raise NoMatch else let rec aux = function [],w -> w | x::lhs,x'::w when x = x' -> aux (lhs,w) | _,_ -> raise NoMatch in rhs @@ apply_rules (aux (lhs,w),new_dir dir lhs) and apply_rules (w,_ as w_and_dir) = if w = [] then [[]] else let rec aux = function [] -> [] | rule::tl -> (try apply_rule_at_beginning rule w_and_dir with NoMatch -> []) @ aux tl in aux rules ;; let apply_rules (w,dir as w_and_dir) = List.map (fun w' -> w,dir,w') (uniq (apply_rules w_and_dir)) ;; let step (l : w list) = uniq (List.flatten (List.map (function w -> List.map (fun x -> x@w) (if List.length (List.filter (fun w -> w = M) w) >= 1 then [[I];[C];[]] else [[I];[C];[M];[]]) ) l)) ;; let mapi f l = let rec aux acc i = function [] -> acc | he::tl -> if i mod 1000 = 0 then begin print_string ("@" ^ string_of_int i ^ " "); flush stdout; end; aux (f he :: acc) (i+1) tl in let res = List.rev (aux [] 1 l) in print_newline (); res ;; let iteri f l = let rec aux i = function [] -> () | he::tl -> if i mod 1000 = 0 then begin print_string ("@" ^ string_of_int i ^ " "); flush stdout; end; f he; aux (i+1) tl in aux 1 l; print_newline (); ;; let normalize (l : w list) = print_endline (string_of_int (List.length l) ^ " nodes to be normalized"); let rels = List.flatten (mapi (fun x -> apply_rules (x,Le) @ apply_rules (x,Ge)) l) in let arcs = List.rev (List.rev_map (function (x,rel,y) -> match rel with Le -> x,y | Ge -> y,x) rels) in let res = uniq arcs in res ;; let visualize describe graph = let module G = struct include Graph.Pack.Digraph;; let edge_attributes _ = [] let default_edge_attributes _ = [] let get_subgraph _ = None let vertex_attributes v = [`Label (describe (Graph.Pack.Digraph.V.label v))] let vertex_name v = "v" ^ string_of_int (Graph.Pack.Digraph.V.label v) let default_vertex_attributes _ = [] let graph_attributes _ = [] end in let module D = Graph.Graphviz.Dot(G) in let ch = open_out "/tmp/comb.dot" in D.output_graph ch graph; close_out ch; ignore (Unix.system ("tred /tmp/comb.dot > /tmp/red.dot")); ignore (Unix.system ("dot -Tps /tmp/red.dot > /tmp/red.ps")); (*Unix.system ("ggv /tmp/red.ps");*) ;; let mk_vertex_and_dsc_vertex = function () -> let cache1 = Hashtbl.create 5393 in let cache2 = Hashtbl.create 5393 in (function w -> try Hashtbl.find cache1 w with Not_found -> let n = let rec aux acc = function [] -> acc | he::tl -> aux (acc * 4 + (match he with I -> 1 | C -> 2 | M -> 3)) tl in aux 0 w in let v = Graph.Pack.Digraph.V.create n in Hashtbl.add cache1 w v; Hashtbl.add cache2 v w; v), (Hashtbl.find cache2) ;; let mk_vertex2 = function () -> let cache1 = Hashtbl.create 5393 in function n -> try Hashtbl.find cache1 n with Not_found -> let v = Graph.Pack.Digraph.V.create n in Hashtbl.add cache1 n v; v ;; let string_compare s1 s2 = let c = compare (String.length s1) (String.length s2) in if c = 0 then String.compare s1 s2 else c ;; let normalize_and_describe norm dsc_vertex = let cache = Hashtbl.create 5393 in let canonicals = Hashtbl.create 5393 in let descriptions = Hashtbl.create 5393 in (function v -> let normalized = norm v in let dsc = dsc_vertex v in if not (List.mem dsc (Hashtbl.find_all cache normalized)) then Hashtbl.add cache normalized dsc; normalized), (function () -> let vertexes = uniq (Hashtbl.fold (fun k _ l -> k::l) cache []) in let xx = mapi (fun v -> v, List.sort string_compare (List.map string_of_w (Hashtbl.find_all cache v)) ) vertexes in iteri (function (_,w::_) -> Hashtbl.add canonicals w () | _ -> ()) xx; let is_not_redundant s = let len = String.length s in if len <= 1 then true else let w = String.sub s 1 (len - 1) in try Hashtbl.find canonicals w; true with Not_found -> false in iteri (function (v,x) -> Hashtbl.add descriptions v (let s = String.concat "=" (List.filter is_not_redundant x) in if s = "" then "." else s)) xx), Hashtbl.find descriptions ;; let classify arcs = print_endline (string_of_int (List.length arcs) ^ " arcs to be classified"); let mk_vertex,dsc_vertex = mk_vertex_and_dsc_vertex () in let graph = Graph.Pack.Digraph.create () in let varcs = mapi (fun (x,y) -> mk_vertex x,mk_vertex y) arcs in iteri (fun (x,y) -> Graph.Pack.Digraph.add_edge graph x y) varcs; print_endline (""); let classes,norm = Graph.Pack.Digraph.Components.scc graph in print_endline (string_of_int classes ^ " classes"); print_endline ("-----"); norm,dsc_vertex,varcs ;; let analyze (norm,dsc_vertex,arcs) = print_endline ("building class graph (" ^ string_of_int (List.length arcs) ^ ")"); let normalize,finish,describe = normalize_and_describe norm dsc_vertex in let arcs = uniq (mapi (fun (x,y) -> normalize x,normalize y) arcs) in let cgraph = Graph.Pack.Digraph.create () in let mk_vertex2 = mk_vertex2 () in List.iter (function (x,y) -> if x <> y then Graph.Pack.Digraph.add_edge cgraph (mk_vertex2 x) (mk_vertex2 y)) arcs; print_endline "finish"; finish (); print_endline "visualize"; visualize describe cgraph; print_endline ("/////"); ;; let rec iter n l = let pkg = classify (normalize l) in if n > 0 then iter (n - 1) (step l) else analyze pkg in iter 6 [[]] ;;