123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314# 1 "src/base/core/owl_graph.ml"(*
* OWL - OCaml Scientific and Engineering Computing
* Copyright (c) 2016-2019 Liang Wang <liang.wang@cl.cam.ac.uk>
*)type'anode={mutableid:int;(* unique identifier *)mutablename:string;(* name of the node *)mutableprev:'anodearray;(* parents of the node *)mutablenext:'anodearray;(* children of the node *)mutableattr:'a;(* indicate the validity *)}typeorder=BFS|DFStypetraversal=PreOrder|PostOrdertypedir=Ancestor|Descendantlet_global_id=ref0letidx=x.idletnamex=x.nameletset_namexs=x.name<-sletparentsx=x.prevletset_parentsxparents=x.prev<-parentsletchildrenx=x.nextletset_childrenxchildren=x.next<-childrenletindegreex=Array.lengthx.prevletoutdegreex=Array.lengthx.nextletdegreex=Array.(lengthx.prev+lengthx.next)letattrx=x.attrletset_attrxa=x.attr<-aletnode?id?(name="")?(prev=[||])?(next=[||])attr=letid=matchidwith|Somei->i|None->(_global_id:=!_global_id+1;!_global_id)in{id;name;prev;next;attr}letconnectparentschildren=Array.iter(funparent->parent.next<-Array.appendparent.nextchildren;Array.iter(funchild->child.prev<-Array.appendchild.prevparents)children)parentsletconnect_descendantsparentschildren=Array.iter(funparent->parent.next<-Array.appendparent.nextchildren)parentsletconnect_ancestorsparentschildren=Array.iter(funchild->child.prev<-Array.appendchild.prevparents)childrenletremove_nodex=letf=funy->y.id<>x.idinArray.iter(funparent->parent.next<-Owl_utils.Array.filterfparent.next)x.prev;Array.iter(funchild->child.prev<-Owl_utils.Array.filterfchild.prev)x.nextletremove_edgesrcdst=src.next<-Owl_utils.Array.filter(funx->x.id<>dst.id)src.next;dst.prev<-Owl_utils.Array.filter(funx->x.id<>src.id)dst.prevletreplace_childchild_0child_1=Array.iter(funparent->letnext=Array.map(funv->ifv.id=child_0.idthenchild_1elsev)parent.nextinparent.next<-next;)child_0.prevletreplace_parentparent_0parent_1=Array.iter(funchild->letprev=Array.map(funv->ifv.id=parent_0.idthenparent_1elsev)child.previnchild.prev<-prev;)parent_0.next(* depth-first search from [x]; [f : node -> unit] is applied to each node;
[next node -> node array] returns the next set of nodes to iterate;
*)letdfs_itertraversalfxnext=leth=Hashtbl.create512inletrec_dfs_itery=ifnot(Hashtbl.memhy.id)then(Hashtbl.addhy.idNone;updatey;)andrelaxy=Array.iter(funz->_dfs_iterz)(nexty)andupdatey=matchtraversalwith|PreOrder->fy;relaxy|PostOrder->relaxy;fyinArray.iter_dfs_iterx(* breadth-first search from [x]; [f : node -> unit] is applied to each node;
[next node -> node array] returns the next set of nodes to iterate.
*)letbfs_itertraversalfxnext=matchtraversalwith|PostOrder->Owl_log.warn"PostOrder BFS not implemented. PreOrder is used."|PreOrder->();leth=Hashtbl.create512inletq=Queue.create()inletrelaxy=Array.iter(funz->ifnot(Hashtbl.memhz.id)then(Hashtbl.addhz.idNone;Queue.pushzq))(nexty)inletupdatey=fy;relaxyinArray.iter(funy->Queue.pushyq)x;Array.iter(funy->Hashtbl.addhy.idNone)x;whilenot(Queue.is_emptyq)dolety=Queue.popqinupdateydoneletiter_ancestors?(order=DFS)?(traversal=PreOrder)fx=matchorderwith|BFS->bfs_itertraversalfxparents|DFS->dfs_itertraversalfxparentsletiter_descendants?(order=DFS)?(traversal=PreOrder)fx=matchorderwith|BFS->bfs_itertraversalfxchildren|DFS->dfs_itertraversalfxchildrenlet_iter?(dir=Ancestor)?order?traversalfx=matchdirwith|Ancestor->iter_ancestors?order?traversalfx|Descendant->iter_descendants?order?traversalfxletfilter_ancestorsfx=lets=Owl_utils.Stack.make()initer_ancestors(funn->iffnthenOwl_utils.Stack.pushsn)x;Owl_utils.Stack.to_arraysletfilter_descendantsfx=lets=Owl_utils.Stack.make()initer_descendants(funn->iffnthenOwl_utils.Stack.pushsn)x;Owl_utils.Stack.to_arraysletfold_ancestorsfax=leta=refainiter_ancestors(funb->a:=f!ab)x;!aletfold_descendantsfax=leta=refainiter_descendants(funb->a:=f!ab)x;!aletiter_in_edges?orderfx=iter_ancestors?order(fundst->Array.iter(funsrc->fsrcdst)dst.prev)xletiter_out_edges?orderfx=iter_descendants?order(funsrc->Array.iter(fundst->fsrcdst)src.next)xletfold_in_edgesfax=leta=refainiter_in_edges(funbc->a:=f!abc)x;!aletfold_out_edgesfax=leta=refainiter_out_edges(funbc->a:=f!abc)x;!a(* TODO *)let_map_f_x=None(* TODO: optimise *)letcopy?(dir=Ancestor)x=let_make_if_not_existshn=ifHashtbl.memhn.id=truethenHashtbl.findhn.idelse(letn'=node~id:n.id~name:n.name~prev:[||]~next:[||]n.attrinHashtbl.addhn'.idn';n')inleth=Hashtbl.create128inlet_copysrcdst=letsrc'=_make_if_not_existshsrcinletdst'=_make_if_not_existshdstinconnect[|src'|][|dst'|]inlet_=matchdirwith|Ancestor->iter_in_edges_copyx|Descendant->iter_out_edges_copyxinArray.map(funn->Hashtbl.findhn.id)x(* TODO *)let_to_array=None(* TODO *)let_to_hashtbl=Noneletnum_ancestorx=letn=ref0initer_ancestors(fun_->n:=!n+1)x;!nletnum_descendantx=letn=ref0initer_descendants(fun_->n:=!n+1)x;!nletlengthx=(num_ancestorx)+(num_descendantx)-(Array.lengthx)letnode_to_strx=Printf.sprintf"[ #%i %s in:%i out:%i ]"x.idx.name(indegreex)(outdegreex)letpp_nodeformatterx=Format.open_box0;Format.fprintfformatter"%s"(node_to_strx);Format.close_box()letto_stringfrom_rootx=lets=ref""inletiter_fun=iffrom_roottheniter_out_edgeselseiter_in_edgesiniter_fun(funuv->s:=Printf.sprintf"%s%i -> %i\n"!su.idv.id)x;!slettopo_sortnodes=lets=Owl_utils.Stack.make()inletfu=Owl_utils.Stack.pushsuiniter_ancestors~order:DFS~traversal:PostOrderfnodes;Owl_utils_stack.to_arrays(* ends here *)