liquid-fixpoint-0.1.0.0: external/fixpoint/toDot.ml
module C = FixConstraint
module StrSet = Set.Make (struct type t = string let compare = compare end)
module StrStrSet = Set.Make (struct type t = StrSet.t let compare = StrSet.compare end)
module S2 = StrSet
module S3 = StrStrSet
module Misc = FixMisc open Misc.Ops
module V = struct
type t = string
let compare = Pervasives.compare
let hash = Hashtbl.hash
let equal = (=)
end
module E = struct
type t = string
let compare = Pervasives.compare
let default = ""
end
module G = Graph.Persistent.Digraph.ConcreteLabeled(V)(E)
module Display = struct
include G
let vertex_name v = "\"" ^ String.escaped v ^ "\""
let graph_attributes _ = []
let default_vertex_attributes _ = []
let vertex_attributes _ = []
let default_edge_attributes _ = []
let edge_attributes e = [`Label (G.E.label e)]
let get_subgraph _ = None
end
module DotOutput = Graph.Graphviz.Dot(Display)
module SCC = Graph.Components.Make(G)
let vertices_of_graph g = G.fold_vertex (fun v vs -> v::vs) g []
let edges_e_of_graph g = G.fold_edges_e (fun e es -> e::es) g []
let set_of_strings = List.fold_left (fun s x -> StrSet.add x s) StrSet.empty
let set_to_string default s =
if StrSet.is_empty s then default else StrSet.elements s |> List.map String.escaped |> String.concat ", "
let edges_e_to_graph es = List.fold_left (fun g e -> G.add_edge_e g e) G.empty es
(* k_1, ..., k_n <: k_0 depends on l_1, ..., l_m <: l_0 iff l_0 = k_i for some 1 \leq i \leq n *)
let t_to_dep t =
let env = C.env_of_t t in
let lhs = C.lhs_of_t t in
let rhs = C.rhs_of_t t in
let tag = try string_of_int (C.id_of_t t) with _ ->
failure "ERROR: t_to_edge: anonymous constraint %s" (C.to_string t) in
let src =
C.kvars_of_reft lhs :: List.map (fun b -> snd b |> C.kvars_of_reft) (C.bindings_of_env env) |>
List.flatten |> List.map snd |> List.map Ast.Symbol.to_string |> set_of_strings in
let dst = C.kvars_of_reft rhs |> List.map snd |> List.map Ast.Symbol.to_string |> set_of_strings in
src, tag, dst
let sccs_to_dot g prefix =
let n, scc_of = SCC.scc g in
let vs = vertices_of_graph g in
Printf.printf "%s #scc = %d\n" prefix n;
for i = 0 to n-1 do
let scc, rest = List.partition (fun v -> scc_of v = i) vs in
let g' = List.fold_left (fun g'' v -> G.remove_vertex g'' v) g rest in
let out = open_out (Printf.sprintf "/tmp/%s-scc-%d.dot" prefix i) in
Printf.printf "%s scc %d %s\n" prefix i (String.concat ", " scc);
DotOutput.output_graph out g';
close_out out
done
let mk_dep_graph ts =
let ds' = List.map t_to_dep ts in
let ds = List.map (fun (src, tag, dst) ->
(if StrSet.is_empty src then StrSet.singleton "start" else src),
tag,
(if StrSet.is_empty dst then StrSet.singleton "error" else dst)
) ds' in
let g =
List.map
(fun (src, tag, dst) ->
Misc.map_partial
(fun (src', tag', dst') ->
let inter = StrSet.inter dst src' in
if StrSet.is_empty inter then
None
else
begin
Printf.printf "self loop %s\n" tag;
Some(G.E.create tag (set_to_string "" inter) tag') (* tag depends on tag' via inter *)
end
) ds
) ds |> List.flatten |> edges_e_to_graph in
let srcs = List.fold_left (fun xs (src, tag, dst) -> src::xs) [] ds' in
(*
let veanu =
List.fold_left (fun xs src ->
S3.fold (fun x ys ->
ys |> S3.add (S2.diff x src) |> S3.add (S2.diff src x) |> S3.add (S2.inter x src)
) xs S3.empty
) (List.hd srcs |> S3.singleton) (List.tl srcs) in
*)
let oc = open_out "/tmp/dep.dot" in
DotOutput.output_graph oc g;
close_out oc;
sccs_to_dot g "dep";
print_endline "start deps";
List.iter (fun (src, tag, dst) ->
Printf.printf "%s <: %s (%s)\n" (set_to_string "" src) (set_to_string "" dst) tag) ds;
print_endline "end deps";
print_endline "start dep graph";
List.iter (fun e ->
Printf.printf "%s - %s -> %s\n" (G.E.src e) (G.E.label e) (G.E.dst e)) (edges_e_of_graph g);
print_endline "end dep graph"
(*
Printf.printf "Veanu %d sets\n%s\n"
(S3.cardinal veanu)
(S3.fold (fun x s ->
(Printf.sprintf "{%s}" (set_to_string "empty" x))::s
) veanu [] |> String.concat ",\n")
*)
let other_graph ts =
let deps = List.map t_to_dep ts in
let srcs, dsts = List.map (fun (s, _, d) -> s, d) deps |> List.split in
let es = List.map (fun (src, tag, dst) ->
G.E.create (set_to_string "start" src) tag (set_to_string "error" dst)
) deps in
let es' = List.fold_left (fun es'' dst ->
Misc.map_partial (fun src ->
if StrSet.diff dst src |> StrSet.is_empty then
Some (G.E.create (set_to_string "error" dst) "" (set_to_string "start" src))
else
None
) srcs ++ es''
) es dsts in
let g = List.fold_left (fun g e -> G.add_edge_e g e) G.empty es' in
g
let t_to_edge t =
let srcs', tag, dsts' = t_to_dep t in
let srcs = if StrSet.is_empty srcs' then ["start"] else StrSet.elements srcs' in
let dsts = if StrSet.is_empty dsts' then ["error"] else StrSet.elements dsts' in
List.fold_left (fun es src -> List.map (G.E.create src tag) dsts ++ es) [] srcs
let to_dot oc ts =
let _ = List.fold_left (fun g e -> G.add_edge_e g e ) G.empty (List.map t_to_edge ts |> List.flatten) in
let g = other_graph ts in
let vs = G.fold_vertex (fun v vs' -> v::vs') g [] in
let n, scc_of = SCC.scc g in
DotOutput.output_graph oc g;
Printf.printf "#scc = %d\n" n;
for i = 0 to n-1 do
let scc, rest = List.partition (fun v -> scc_of v = i) vs in
let g' = List.fold_left (fun g'' v -> G.remove_vertex g'' v) g rest in
let out = open_out (Printf.sprintf "/tmp/scc-%d.dot" i) in
Printf.printf "scc %d %s\n" i (String.concat ", " scc);
DotOutput.output_graph out g';
close_out out
done;
mk_dep_graph ts