123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102(** Representation of trees as graphviz files.
{{:https://graphviz.org}Graphviz} is a graph visualization software. This
module handles the conversion from {!type:Core.Term.dtree} data structures
in the [dot] language that can be interpreted by graphviz.
See the chapter [doc/options.md#printing-decision-trees] of the
documentation for more information. *)openLplibopenBaseopenTimedopenCoreopenTermopenTree_type(** Printing hint for conversion to graphviz. *)typedot_term=|DotDefa(* Default case *)|DotAbstofint|DotProdofint|DotConsofTC.t|DotSuccess|DotFailure(** [to_dot ppf sym] prints a dot graphviz representation of the tree of
symbol [sym] on [ppf]. Each node of the tree embodies a pattern matrix. The
label of a node is the column index in the matrix on which the matching is
performed to give birth to the child node. The label on the edge between a
node and one of its children represents the term matched to generate the
next pattern matrix (the one of the child node). *)letto_dot:Format.formatter->sym->unit=funppfs->letoutput_treeppftree=letdotterm:dot_termpp=funppfdh->letvar_px="v"inmatchdhwith|DotAbst(id)->outppf"λ%s%d"var_pxid|DotProd(id)->outppf"Π%s%d"var_pxid|DotDefa->outppf"*"|DotCons(Symb(_,n,a))->outppf"%s<sub>%d</sub>"na|DotCons(Vari(i))->outppf"%s%d"var_pxi|DotSuccess->outppf"✓"|DotFailure->outppf"✗"inlettcstr:tree_condpp=funppfcstr->letar=Array.ppint" "inmatchcstrwith|CondNL(i,j)->outppf"%d ≡ %d"ij|CondFV(i,vs)->outppf"%a ⊆ FV(%d)"arvsiinletnode_count=ref0in(* [write_tree n u v] writes tree [v] obtained from tree number [n] with a
switch on [u] ({!constructor:None} if default). *)letrecwrite_treefather_lswont=incrnode_count;matchtwith|Leaf(_,(a,_))->let_,acte=Bindlib.unmbindainoutppf"@ %d [label=\"%a\"];"!node_countPrint.termacte;outppf"@ %d -- %d [label=<%a>];"father_l!node_countdottermswon|Node({swap;children;store;abstraction=abs;default;product})->lettag=!node_countin(* Create node *)outppf"@ %d [label=\"%d\"%s];"tagswap(ifstorethen" shape=\"box\""else"");(* Create edge *)outppf"@ %d -- %d [label=<%a>];"father_ltagdottermswon;TCMap.iter(funse->write_treetag(DotCons(s))e)children;Option.iter(fun(x,t)->write_treetag(DotAbst(x))t)abs;Option.iter(fun(x,t)->write_treetag(DotProd(x))t)product;Option.iter(write_treetagDotDefa)default|Cond({ok;cond;fail})->lettag=!node_countinoutppf"@ %d [label=<%a> shape=\"diamond\"];"tagtcstrcond;outppf"@ %d -- %d [label=<%a>];"father_ltagdottermswon;write_treetagDotSuccessok;write_treetagDotFailurefail|Eos(l,r)->lettag=!node_countinoutppf"@ %d [label=\"\" shape=\"triangle\"];"tag;outppf"@ %d -- %d [label=<%a>];"father_ltagdottermswon;write_treetagDotFailurel;write_treetagDotSuccessr|Fail->outppf"@ %d [label=<!>];"!node_count;outppf"@ %d -- %d [label=\"!\"];"father_l!node_countinoutppf"graph {@[<v>";beginmatchtreewith(* First step must be done to avoid drawing a top node. *)|Node{swap;store;children;default;abstraction;product}->outppf"@ 0 [label=\"%d\"%s];"swap(ifstorethen" shape=\"box\""else"");TCMap.iter(funswc->write_tree0(DotCons(sw))c)children;Option.iter(fun(x,t)->write_tree0(DotAbst(x))t)abstraction;Option.iter(fun(x,t)->write_tree0(DotProd(x))t)product;Option.iter(funt->write_tree0DotDefat)default|Leaf(_)->()|_->assertfalseend;outppf"@.}@\n@?"inoutput_treeppf(Lazy.force(snd!(s.sym_dtree)))