123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363(*
POMAP - Library for manipulating partially ordered maps
Copyright (C) 2001-2006 Markus Mottl (OEFAI)
email: markus.mottl@gmail.com
WWW: http://www.ocaml.info
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*)(** Specification of a partial order relation *)moduletypePARTIAL_ORDER=sigtypeel(** Element type *)typeord=Unknown|Lower|Equal|Greatervalcompare:el->el->ordend(** Interface to partially ordered maps *)moduletypePOMAP=sig(** {6 Modules and types} *)moduleStore:Store_intf.STORE(** Store module used to store nodes of the partially ordered map. *)openStoretypekey(** Type of map keys *)type(+'a)node(** Type of nodes in the partially ordered map *)type(+'a)pomap(** Type of partially ordered maps *)(** Type of result originating from an [add_find] operation *)type(+'a)add_find_result=|FoundofIx.t*'anode|AddedofIx.t*'anode*'apomap(** {6 Map-constructors } *)valempty:'apomap(** The empty partially ordered map. *)valsingleton:key->'a->'apomap(** [singleton k el] @return a partially ordered map containing as only
binding the one from [k] to [el]. *)(** {6 Information on maps} *)valis_empty:'apomap->bool(** [is_empty pm] tests whether partially ordered map [pm] is empty. *)valcardinal:'apomap->int(** [cardinal pm] @return the number of elements in [pm]. *)(** {6 Adding and removing} *)valadd:key->'a->'apomap->'apomap(** [add k el pm] @return a partially ordered map containing the same
bindings as [pm], plus a binding of [k] to [el]. If [k] was already
bound in [pm], its previous binding disappears. *)valadd_node:'anode->'apomap->'apomap(** [add_node node pm] @return a partially ordered map containing
the same bindings as [pm] plus a binding as represented by
[node]. If the associated key already existed in [pm], its previous
binding disappears. *)valremove:key->'apomap->'apomap(** [remove k pm] @return a map containing the same bindings as
[pm] except for the node with key [k]. *)valremove_node:'anode->'apomap->'apomap(** [remove_node node pm] @return a map containing the same bindings as
[pm] except for the one with the key of [node]. *)valremove_ix:Ix.t->'apomap->'apomap(** [remove_ix ix pm] @return a map containing the same bindings as
[pm] except for the node indexed by [ix].
@raise Not_found if [ix] does not index any node. *)valtake:key->'apomap->Ix.t*'anode*'apomap(** [take k pm] @return a tuple [(ix, node, map)], where [ix] is
the index of the [node] associated with key [k] in [pm], and [map]
is [pm] without this element.
@raise Not_found if there is no binding for [key]. *)valtake_ix:Ix.t->'apomap->'anode*'apomap(** [take_ix ix pm] @return a tuple [(n, m)], where [n] is the node
associated with index [ix], and [m] is a map without this element.
@raise Not_found if [ix] does not index any node. *)valadd_find:key->'a->'apomap->'aadd_find_result(** [add_find k el pm] similar to [add], but if the binding did already
exist, then [Found (ix, node)] will be returned to indicate the
index and node under which key [k] is bound. Otherwise [Added
(new_ix, new_pm)] will be returned to indicate that [k] was bound
under new index [new_ix] in the partially ordered map [new_pm]. *)valadd_fun:key->'a->('a->'a)->'apomap->'apomap(** [add_fun k el f pm] similar to [add], but if the binding already
existed, then function [f] will be applied to the previously bound
data. Otherwise the binding will be added as in [add]. *)(** {6 Scanning and searching} *)valmem:key->'apomap->bool(** [mem k pm] @return [true] if [pm] contains a binding for key [k]
and [false] otherwise. *)valmem_ix:Ix.t->'apomap->bool(** [mem el pm] @return [true] if [pm] contains a binding for data
element [el] and [false] otherwise. *)valfind:key->'apomap->Ix.t*'anode(** [find k pm] @return a tuple [(ix, node)], where [ix] is the index
of key [k] and [node] its associated node in map [pm].
@raise Not_found if no such binding exists. *)valfind_ix:Ix.t->'apomap->'anode(** [find_ix ix pm] @return the node associated with index [ix] in map [pm].
@raise Not_found if such a node does not exist. *)valchoose:'apomap->Ix.t*'anode(** [choose pm] @return a tuple [(ix, node)], where [ix] is the
index of the [node] of some unspecified element in [pm].
@raise Not_found if [pm] is empty. *)valfilter:(Ix.t->'anode->bool)->'apomap->'apomap(** [filter p pm] @return the map of all elements in [pm] that
satisfy [p]. *)valpartition:(Ix.t->'anode->bool)->'apomap->'apomap*'apomap(** [partition p pm] @return a pair of maps [(pm1, pm2)], where
[pm1] is the map of all the elements of [pm] that satisfy the
predicate [p], and [pm2] is the map of all the elements of [pm]
that do not satisfy [p]. *)(** {6 Iterators} *)valiter:('anode->unit)->'apomap->unit(** [iter f pm] applies [f] to all bound nodes in map [pm].
The order in which the nodes are passed to [f] is unspecified. Only
current bindings are presented to [f]: bindings hidden by more
recent bindings are not passed to [f]. *)valiteri:(Ix.t->'anode->unit)->'apomap->unit(** [iteri f pm] same as {!iter}, but function [f] also receives
the index associated with the nodes. *)valmap:('anode->'b)->'apomap->'bpomap(** [map f pm] @return a map with all nodes in [pm] mapped from
their original value to identical nodes whose data element is in
the codomain of [f]. The order in which nodes are passed to [f]
is unspecified. *)valmapi:(Ix.t->'anode->'b)->'apomap->'bpomap(** [mapi f pm] same as {!map}, but function [f] also receives
the index associated with the nodes. *)valfold:('anode->'b->'b)->'apomap->'b->'b(** [fold f pm a] computes [(f nN ... (f n1 a) ...)], where [n1 ... nN]
are the nodes in map [pm]. The order in which the nodes are
presented to [f] is unspecified. *)valfoldi:(Ix.t->'anode->'b->'b)->'apomap->'b->'b(** [foldi f pm a] same as {!fold}, but function [f] also receives
the index associated with the nodes. *)valtopo_fold:('anode->'b->'b)->'apomap->'b->'b(** [topo_fold f pm a] computes [(f nN ... (f n1 a) ...)], where
[n1 ... nN] are the nodes in map [pm] sorted in ascending
topological order. Slower than [fold]. *)valtopo_foldi:(Ix.t->'anode->'b->'b)->'apomap->'b->'b(** [topo_foldi f pm a] same as {!topo_fold}, but function [f]
also receives the index associated with the nodes. *)valtopo_fold_ix:(Ix.t->'b->'b)->'apomap->'b->'b(** [topo_fold_ix f pm a] same as {!topo_fold}, but function [f]
only receives the index associated with the nodes. *)valrev_topo_fold:('anode->'b->'b)->'apomap->'b->'b(** [rev_topo_fold f pm a] computes [(f nN ... (f n1 a) ...)], where
[n1 ... nN] are the nodes in map [pm] sorted in descending
topological order. Slower than [fold]. *)valrev_topo_foldi:(Ix.t->'anode->'b->'b)->'apomap->'b->'b(** [rev_topo_foldi f pm a] same as {!rev_topo_fold}, but function [f]
also receives the index associated with the nodes. *)valrev_topo_fold_ix:(Ix.t->'b->'b)->'apomap->'b->'b(** [rev_topo_fold_ix f pm a] same as {!rev_topo_fold}, but function [f]
only receives the index associated with the nodes. *)valchain_fold:('anodelist->'b->'b)->'apomap->'b->'b(** [chain_fold f pm a] computes [(f cN ... (f c1 a) ...)], where
[c1 ... cN] are the ascending chaines of nodes in map [pm]. Only
useful for small maps, because of potentially exponential
complexity. *)valchain_foldi:((Ix.t*'anode)list->'b->'b)->'apomap->'b->'b(** [chain_foldi f pm a] same as {!chain_fold}, but function [f]
receives chains including the index associated with the nodes. *)valrev_chain_fold:('anodelist->'b->'b)->'apomap->'b->'b(** [rev_chain_fold f pm a] computes [(f cN ... (f c1 a) ...)], where
[c1 ... cN] are the descending chaines of nodes in map [pm]. Only
useful for small maps, because of potentially exponential
complexity. *)valrev_chain_foldi:((Ix.t*'anode)list->'b->'b)->'apomap->'b->'b(** [rev_chain_foldi f pm a] same as {!rev_chain_fold}, but function [f]
receives chains including the index associated with the nodes. *)(** {6 Set-like map-operations} *)valunion:'apomap->'apomap->'apomap(** [union pm1 pm2] merges [pm1] and [pm2], preserving the
bindings of [pm1]. *)valinter:'apomap->'apomap->'apomap(** [inter pm1 pm2] intersects [pm1] and [pm2], preserving the
bindings of [pm1]. *)valdiff:'apomap->'apomap->'apomap(** [diff pm1 pm2] removes all elements of [pm2] from [pm1]. *)(** {6 Node-creators and accessors} *)valcreate_node:key->'a->Ix.Set.t->Ix.Set.t->'anode(** [create_node k el sucs prds] @return a node with key [k], data
element [el], successors [sucs] and predecessors [prds]. *)valget_key:'anode->key(** [get_key n] @return the key associated with node [n]. *)valget_el:'anode->'a(** [get_el n] @return the data element associated with node [n]. *)valget_sucs:'anode->Ix.Set.t(** [get_sucs n] @return the successors associated with node [n]. *)valget_prds:'anode->Ix.Set.t(** [get_prds n] @return the predecessors associated with node [n]. *)valset_key:'anode->key->'anode(** [set_key n k] sets the key of node [n] to [k] and returns new node. *)valset_el:'anode->'a->'anode(** [set_el n el] sets the data element of node [n] to [el] and
returns new node. *)valset_sucs:'anode->Ix.Set.t->'anode(** [set_sucs n sucs] set the successors of node [n] to [sucs] and
returns new node. *)valset_prds:'anode->Ix.Set.t->'anode(** [set_prds n prds] set the predecessors of node [n] to [prds]
and returns new node. *)(** {6 Map-accessors} *)valget_nodes:'apomap->'anodeStore.t(** [get_nodes pm] @return the store of nodes associated
with partially ordered map [pm]. This store represents the
Hasse-graph of the nodes partially ordered by their keys. *)valget_top:'apomap->Ix.Set.t(** [get_top pm] @return the set of node indices of nodes that are
greater than any other node in [pm] but themselves. *)valget_bot:'apomap->Ix.Set.t(** [get_bot pm] @return the set of node indices of nodes that are
lower than any other node in [pm] but themselves. *)(** {6 Operations over equivalences of data elements} *)valremove_eq_prds:('a->'a->bool)->'apomap->'apomap(** [remove_eq_prds eq pm] @return a map containing the same
bindings as [pm] except for nodes whose non-empty predecessors
all have the same data element as identified by [eq]. *)valfold_eq_classes:('a->'a->bool)->('a->'apomap->'b->'b)->'apomap->'b->'b(** [fold_eq_classes eq f pm a] factorizes [pm] into maximal
equivalence classes of partial orders: all bindings in each
class have equivalent data elements as identified by [eq] and
are connected in the original Hasse-diagram. This function then
computes [(f ec_elN ecN ... (f ec_el1 ec1 a))], where [ec1 ... ecN]
are the mentioned equivalence classes in unspecified order, and
[ec_el1 ... ec_elN] are their respective common data elements. *)valfold_split_eq_classes:('a->'a->bool)->('a->'apomap->'b->'b)->'apomap->'b->'b(** [fold_split_eq_classes eq f pm a] same as {!fold_eq_classes},
but the equivalence classes are split further so that no element
of other classes would fit between its bottom and top elements.
It is unspecified how non-conflicting elements are assigned to
upper or lower classes! *)valpreorder_eq_classes:('a->'a->bool)->'apomap->'apomaplist(** [preorder_eq_classes eq pm] @return a preordered list of
equivalence classes, the latter being defined as in
[fold_split_eq_classes]. *)valtopo_fold_reduced:('a->'a->bool)->('anode->'b->'b)->'apomap->'b->'b(** [topo_fold_reduced eq f pm a] computes [(f nN ... (f n1 a) ...)],
where [n1 ... nN] are those nodes in map [pm] sorted in ascending
topological order, whose data element is equivalent as defined by
[eq] to the one of lower elements if there are no intermediate
elements that violate this equivalence. *)(** {6 Unsafe operations - USE WITH CAUTION!} *)valunsafe_update:'apomap->Ix.t->'anode->'apomap(** [unsafe_update pm ix node] updates the node associated with node
index [ix] in map [pm] with [node]. The Hasse-diagram associated
with the partially ordered map [pm] may become inconsistent if
the new node violates the partial order structure. This can lead
to unpredictable results with other functions! *)valunsafe_set_nodes:'apomap->'anodeStore.t->'apomap(** [unsafe_set_nodes pm s] updates the node store associated with map
[pm] with [s]. This assumes that [s] stores a consistent
Hasse-diagram of nodes. *)valunsafe_set_top:'apomap->Ix.Set.t->'apomap(** [unsafe_set_top pm set] updates the index of top nodes in
map [pm] with [set]. This assumes that the nodes referenced by
the node indices in [set] do not violate the properties of the
Hasse-diagram of [pm]. *)valunsafe_set_bot:'apomap->Ix.Set.t->'apomap(** [unsafe_set_bot pm set] updates the index of bottom nodes
in map [pm] with [set]. This assumes that the nodes referenced
by the node indices in [set] do not violate the properties of the
Hasse-diagram of [pm]. *)end