123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140(******************************************************************************)(* *)(* FlatUnionFind *)(* *)(* François Pottier, Inria Paris *)(* *)(* Copyright 2024--2024 Inria. All rights reserved. This file is *)(* distributed under the terms of the GNU Library General Public *)(* License, with an exception, as described in the file LICENSE. *)(* *)(******************************************************************************)(**This signature describes the result of the functor {!FlatUnionFind.Make}. *)moduletypeUF=sig(**[point] is the type of a point in the union-find data structure. It is
an abstract type. The keyword [private] indicates that a point [x] can
be converted to an integer index, by writing [x :> int]. This integer
index lies in the semi-open interval from 0 to [population()]. The
conversion in the reverse direction is not permitted. *)typepoint=privateinttypet=pointtypepopulation=int(**[population()] is the total number of points created so far. *)valpopulation:unit->population(**[iter f] applies the user-supplied function [f] to every point
that was ever created (whose creation was not undone via [drop]). *)valiter:(point->unit)->unit(**[fresh()] creates a new point, which forms a new singleton
equivalence class. *)valfresh:unit->point(**[drop x] undoes the creation of the point [x]. This is permitted only
if no new point was created since [x] was created (or if those new
points were themselves dropped) and no [union] operation took place
since [x] was created. This operation is unsafe: the user must promise
to not use the point [x] afterwards. *)valdrop:point->unit(**If runtime assertions are enabled, then [validate x] checks that
the point [x] is a valid point, and fails otherwise. [drop] is
the only operation that can cause a point to become invalid. *)valvalidate:point->unit(**[find x] finds the current representative element of the
equivalence class of the point [x]. *)valfind:point->point(**[is_representative x] determines whether [x] is currently
the representative element of its equivalence class. *)valis_representative:point->bool(**[equal x y] determines whether [x] and [y] are equal,
that is, whether they are the same point.
It is equivalent to [(x :> int) = (y :> int)]. *)valequal:point->point->bool(**[compare] is a total order on points.
[compare x y] is equivalent to [Int.compare (x :> int) (y :> int)]. *)valcompare:point->point->int(**[hash] is a hash function on points.
[hash x] equivalent to [Int.hash (x :> int)]. *)valhash:point->int(**[show x] produces a human-readable representation of the point [x]. *)valshow:point->string(**[equiv x y] determines whether [x] and [y] are equivalent,
that is, whether they are members of the same equivalence
class. (If they are now, then they will be forever.) *)valequiv:point->point->bool(**If [equiv x y] is true, then [union x y] has no observable effect.
Otherwise, [union x y] merges the equivalence classes of the points [x]
and [y]. In either case, after the call, [equiv x y] is true.
[union x y] returns a point [z] such that [equiv x z] and [equiv y z]
and [is_representative z] are true. *)valunion:point->point->point(**The submodule [Vector] offers vectors that contain points. *)moduleVector:Hector.MONOVECTORwithtypeelement=point(**The submodule [HashSet] offers hash sets that contain points. It
is a functor: an equivalence relation on points must be chosen by
the user. *)moduleHashSet(_:sigtypet=pointvalhash:point->intvalequal:point->point->boolend):Hachis.HashSet.SETwithtypeelement=pointend(* -------------------------------------------------------------------------- *)(**This signature describes the result of the functor {!FlatUnionFind.Wrap}. *)moduletypeUFD=sigtypedata(**This signature extends {!UF} with new functionality: with every
equivalence class, a datum of type [data] is associated. To create a
new point, the function [fresh] cannot be used; instead, {!make} must
be used. *)includeUF(**[make v] creates a new point, which forms a new singleton equivalence
class, and associates the value [v] with this class. *)valmake:data->point(**[get x] returns the value that is currently associated with the
equivalence class of the point [x]. *)valget:point->data(**[set x v] associates the value [v] with the equivalence class of the
point [x]. *)valset:point->data->unit(**[eq] is a synonym for [equiv]. *)valeq:point->point->bool(**If [eq x y] is true initially, then [merge f x y] has no observable
effect. Otherwise, [merge f x y] merges the equivalence classes of the
points [x] and [y] and associates the value [f vx vy] with the new class,
where [vx] and [vy] are the values initially associated with the classes
of [x] and [y]. The function [f] is {i not} allowed to access the
union-find data structure. *)valmerge:(data->data->data)->point->point->point(**/**)valfresh:unitend