/* * Copyright 2023 Jakob Schneider Villumsen * * Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE.md file. */////// Type of mutable disjoint sets (union-find), and its functions.///pubmod MutDisjointSets {////// Type of mutable disjoint sets (union-find).////// Uses union-by-rank and path compression.///pubstructMutDisjointSets[t: Type, r: Region] { rc: Region[r], forest: MutMap[t, Node[t, r], r] }////// Represents an element in the disjoint set forest.///structNode[t: Type, r: Region] { rc: Region[r], value: t, mut parent: Option[Node[t, r]], mut rank: Int32 }/// Functions on the nodes of the disjoint set forest.mod Node {/// Returns the parent of the node `n`, or `None` if `n` is a root.pubdefparent(n: Node[t, r]): Option[Node[t, r]] \ r = n->parent/// Returns the rank of the node `n`.pubdefrank(n: Node[t, r]): Int32 \ r = n->rank/// Increments the rank of the node `n` by one.pubdefincrementRank(n: Node[t, r]): Unit \ r = n->rank = n->rank +1/// Sets the parent of the node `n` to `newParent`.pubdefsetParent(newParent: Option[Node[t, r]], n: Node[t, r]): Unit \ r = n->parent = newParent/// Returns the element stored in the node `n`.pubdefvalue(n: Node[t, r]): t = n->value }////// Returns new and empty `MutDisjointSets` in the region `rc`.///pubdefempty(rc: Region[r]): MutDisjointSets[t, r] \ r =new MutDisjointSets @ rc {rc = rc, forest = MutMap.empty(rc)}////// Updates `s` with a new disjoint set containing `x`/// if `x` is not already in `s`.///pubdefmakeSet(x: t, s: MutDisjointSets[t, r]): Unit \ rwithOrder[t] = {defsingleton(rc, y) = {new MutDisjointSets.Node @ rc {rc = rc, value = y, parent = None, rank = 0} };if (notmemberOf(x, s)) {MutMap.put(x, singleton(s->rc, x), s->forest) } else {() } }////// Updates `s` with the elements of the iterable `m`.///pubdefmakeSets(m: m, s: MutDisjointSets[elt, r]): Unit \ (r + Iterable.Aef[m]) withIterable[m], Order[elt] whereIterable.Elm[m] ~ elt = regionrc {Iterable.iterator(rc, m) |> Iterator.forEach(x -> makeSet(x, s)) }////// Returns `true` iff `x` is a member of `s`.///pubdefmemberOf(x: t, s: MutDisjointSets[t, r]): Bool \ rwithOrder[t] = {MutMap.memberOf(x, s->forest) }////// Returns the representative / root of the set that contains `x`.///pubdeffind(x: t, s: MutDisjointSets[t, r]): Option[t] \ rwithOrder[t] =findSet(x, s) |> Option.map(Node.value)////// Returns the representative / root `Node` of the set that contains `x`.///deffindSet(x: t, s: MutDisjointSets[t, r]): Option[Node[t, r]] \ rwithOrder[t] = {deffindRoot(updateAtRoot, y) = {letparent = Node.parent(y);matchparent {case Some(p) => {findRoot(y :: updateAtRoot, p) }case None =>updateAtRoot |> List.forEach(Node.setParent(Some(y)));y } };MutMap.get(x, s->forest) |> Option.map(findRoot(Nil)) }////// Merges the sets that contain `x` and `y` if both `x` and `y` are in `s`./// If `x` and `y` have the same rank, then `y` becomes the new parent of `x`./// Otherwise, the element with the highest rank becomes the new representative.////// The rank of an element is determined by how many times it is made/// the new representative after a union with another element of the/// same rank.////// Further reading:/// https://en.wikipedia.org/wiki/Disjoint-set_data_structure///pubdefunion(x: t, y: t, s: MutDisjointSets[t, r]): Unit \ rwithOrder[t] =deflink(x1, y1) = {if (notequal(x1, y1)) {letxRank = Node.rank(x1);letyRank = Node.rank(y1);if (xRank>yRank) {Node.setParent(Some(x1), y1) } else {Node.setParent(Some(y1), x1) };if (xRank==yRank) {Node.incrementRank(y1) } else {() } } else {() } };match (findSet(x, s), findSet(y, s)) {case (Some(xn), Some(yn)) => link(xn, yn)case (Some(_), None) => {makeSet(y, s);union(x, y, s) }case (None, Some(_)) => {makeSet(x, s);union(x, y, s) }case (None, None) => {makeSet(x, s);makeSet(y, s);union(x, y, s) } }////// Returns true if `x` and `y` are in the same disjoint set./// This is equivalent to having the same representative / root./// Returns false if either `x` or `y` is not in `s`.///pubdefequivalent(x: t, y: t, s: MutDisjointSets[t, r]): Bool \ rwithOrder[t] =match (findSet(x, s), findSet(y, s)) {case (Some(xn), Some(yn)) => equal(xn, yn)case_ => false }////// Returns true if `x` and `y` have the same value.///defequal(x: Node[t, r], y: Node[t, r]): BoolwithEq[t] =Node.value(x) ==Node.value(y)////// Returns the number of elements in `s`.///pubdefsize(s: MutDisjointSets[t, r]): Int32 \ rwithOrder[t] =MutMap.size(s->forest)}