How can I represent an automaton graphically from

2019-09-11 19:06发布

问题:

I made a record called automaton containing the 5 fields required to represent an automaton I'm supposed to use graphics to represent every state and transition from the transitions list without using for or while loops only recursive functions

transitions :(int*char*int) list;

回答1:

It might be easiest to use graphviz to do the actual drawing. It automatically draws a graph from a list of nodes and edges, which is exactly what your input is. The function fmt_transition generates one edge, the function fmt_transitions lifts it via pp_print_list to lists of transitions and wraps it into the correct header.

let fmt_transition fmt (inedge,by,outedge) =
  Format.fprintf fmt "@[%d -> %d [label=\"%c\"];@]" inedge outedge by

let fmt_transitions fmt =
  Format.fprintf fmt "@[<v 2>digraph output {@,%a@,@]}@,@."
    (Format.pp_print_list fmt_transition)

If we try it on some test data, we get the test file we wanted:

let test1 = [ (1,'a',2); (2,'b',1); (1,'b',1)] in
fmt_transitions Format.std_formatter test1;;

results in:

digraph output
{
   1 -> 2 [label="a"];
   2 -> 1 [label="b"];
   1 -> 1 [label="b"];
}

The call to graphviz is:

dot -T pdf -o output.pdf < input.dot

If you call it directly from ocaml, you can also pipe the data directly into dot without writing it to disk first.

Alternatively, you can also use an external viewer like gv:

let call_dot data =
  let cmd = "dot -Tps | gv -" in
  let (sout, sin, serr) as channels =
    Unix.open_process_full cmd (Unix.environment ()) in
  let fmt = Format.formatter_of_out_channel sin in
  Format.fprintf fmt "%a@." fmt_transitions data;
  channels

let cleanup channels =
  (* missing: flush channels, empty buffers *)
  Unix.close_process_full channels

The call call_dot test1 |> cleanup will send the data to dot and open ghostview. To prevent hitting the limit of open files, one shout await the termination of the process and close the channels, which is done in cleanup.

If you want to use an image library instead, you might want to replace the definition of cmd by "dot -Tpng" and read the image data from stdin before you call cleanup.