Module PolymorphicValued.PersistentArrayNCA
Persistent array based polymorphic labeled union-find lattice with values. Same as PersitentArray, but builds join on the nearest common ancestor instead of one of the branches.
Parameters
module Config : Parameters.PERSISTENT_ARRAY_CONFIGmodule Node : Parameters.POLYMORPHIC_NODEmodule Relation : Parameters.POLYMORPHIC_GROUPmodule Value :
Parameters.POLYMORPHIC_VALUE
with type ('a, 'b) relation = ('a, 'b) Relation.t
and type 'a node = 'a Node.tSignature
include Sig.POLYMORPHIC_LABELED_UNION_FIND_LATTICE
with type 'a node = 'a Node.t
with type ('a, 'b) relation = ('a, 'b) Relation.t
type 'a node = 'a Node.tThe type of union-find nodes i.e. the elements of the partition set
type ('a, 'b) relation = ('a, 'b) Relation.tThe type of relations. A ('a, 'b) relation relates an 'a node and a 'b node. Mathematically, relations have a group structure.
The true type of find is 'a t -> 'a node -> ∃ 'b. 'b t * ('a, 'b) relation * 'b value option Since we can't express existential types directly in OCaml, we need this wrapper type.
val make : int -> tCreate a new union-find, see UNION_FIND_LATTICE.make
val find : t -> 'a node -> 'a find_resultfind uf x returns:
- the reprensentative of
x - the relation between
xand its representative It performs both the 'find' and 'get_value' operations from the paper.
val add_relation :
t ->
'a node ->
'b node ->
('a, 'b) relation ->
(t, ('a, 'b) relation) Stdlib.resultadd_relation uf x y r returns a new persistent union-find, where the relation x --(r)--> y was added.
This is the union operation of classical union find, only this time it takes the new relation as an extra argument.
This fails if x and y were already related by a different relation in uf. In that case, that other relation is returned.
check_related uf x y checks if x and y are in the same relational class in uf. If so, the relation between them is returned. Otherwise, None is returned.
Lattice operations
incl uf_a uf_b is lattice inclusion, uf_a <= uf_b, i.e. forall x y, if check_related uf_b x y then check_related uf_a x y
join uf_a uf_b is the least upper-bound of uf_a and uf_b, i.e. forall x y, check_related (join uf_a uf_b) x y iff check_related uf_b x y and check_related uf_a x y
Existential wrapper for a relation between two nodes, used by meet.
val meet : t -> t -> t * wrapped_relation listmeet uf_a uf_b is a pair meet, extra_rel:
meetis (one of) the greatest lower bound ofuf_aanduf_b. It contains all relations ofuf_aand some of the relations ofuf_b. (All nodes that are related inuf_bare still related, but their relation might be changed, as all relations may not be preserved)extra_relis a minimal list of relations fromuf_bthat could not be preserved. For example, ifuf_acontainsx --(r)--> yanduf_bcontainsx --(r')--> ywithr != r',r'will either be in the list, or a transitive/symmetric consequence of relations that are in the list
Testing and debugging
To compare persistent union-find with non-persistent version, we need an explicit copy operation. This is Fun.id for all persistent versions.
val check_invariants : t -> string optioncheck_invariants uf is used in testing, to assert that the data-structures internal invariants, if any, are still true after complex operations.
Returns None if they hold, Some error_msg otherwise.
val pretty : Stdlib.Format.formatter -> t -> unitpretty-printer
type 'a value = 'a Value.tThe type of values assigned to relational classes. Relation act as group actions on values: given a ('a, 'b) relation, we can transform a 'a value into a 'b value
get_value uf x returns the value attached to x, if it exists.
set_value ~intersect uf n v returns a new union-find, where the value attached to the class of n is now v. If intersect is true, this value will be combined with the previous value (should one exists) via Parameters.VALUE.meet.