123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136(******************************************************************************)(* *)(* Fix *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright Inria. All rights reserved. This file is distributed under the *)(* terms of the GNU Library General Public License version 2, with a *)(* special exception on linking, as described in the file LICENSE. *)(* *)(******************************************************************************)(* Using doubly-linked adjacency lists, one could implement [predecessors] in
worst-case linear time with respect to the length of the output list,
[set_successors] in worst-case linear time with respect to the length of
the input list, and [clear_successors] in worst-case linear time with
respect to the number of edges that are removed. We use a simpler
implementation, based on singly-linked adjacency lists, with deferred
removal of edges. It achieves the same complexity bounds, except
[predecessors] only offers an amortized complexity bound. This is good
enough for our purposes, and, in practice, is more efficient by a constant
factor. This simplification was suggested by Arthur Charguéraud. *)(* -------------------------------------------------------------------------- *)(* Nodes and edges. *)type'datanode={(* The client information associated with this node. *)data:'data;(* This node's incoming and outgoing edges. *)mutableoutgoing:'dataedgelist;mutableincoming:'dataedgelist;(* A transient mark, always set to [false], except when checking
against duplicate elements in a successor list. *)mutablemarked:bool;}and'dataedge={(* This edge's nodes. Edges are symmetric: source and destination are not
distinguished. Thus, an edge appears both in the outgoing edge list of
its source node and in the incoming edge list of its destination node.
This allows edges to be easily marked as destroyed. *)node1:'datanode;node2:'datanode;(* Edges that are destroyed are marked as such, but are not immediately
removed from the adjacency lists. *)mutabledestroyed:bool;}(* -------------------------------------------------------------------------- *)(* Node creation. *)letcreatedata={data=data;outgoing=[];incoming=[];marked=false;}(* Data access. *)letdatanode=node.data(* [follow src edge] returns the node that is connected to [src] by [edge].
Time complexity: constant. *)letfollowsrcedge=ifedge.node1==srcthenedge.node2elsebeginassert(edge.node2==src);edge.node1end(* The [predecessors] function removes edges that have been marked
destroyed. The cost of removing these has already been paid for,
so the amortized time complexity of [predecessors] is linear in
the length of the output list. *)letpredecessors(node:'datanode):'datanodelist=letpredecessors=List.filter(funedge->notedge.destroyed)node.incominginnode.incoming<-predecessors;List.map(follownode)predecessors(* [link src dst] creates a new edge from [src] to [dst], together
with its reverse edge. Time complexity: constant. *)letlink(src:'datanode)(dst:'datanode)=letedge={node1=src;node2=dst;destroyed=false;}insrc.outgoing<-edge::src.outgoing;dst.incoming<-edge::dst.incomingletset_successors(src:'datanode)(dsts:'datanodelist)=assert(src.outgoing=[]);letrecloop=function|[]->()|dst::dsts->ifdst.markedthenloopdsts(* skip duplicate elements *)elsebegindst.marked<-true;linksrcdst;loopdsts;dst.marked<-falseendinloopdstsletclear_successorsnode=List.iter(funedge->assert(notedge.destroyed);edge.destroyed<-true;)node.outgoing;node.outgoing<-[]