Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Equivalence classes and union/find in a functional language

For an automata algorithm, I require a fast Union-Find data structure in a functional language. Since I need to formally prove the correctness of the data structure, I would prefer a simple structure.

What I am trying to do is to compute the equivalence classes of elements in a set S w.r.t. a relation R ⊆ S × S. What I want to get out in the end is some function f: S → S that maps any element of S to a (canonical) representative of its R-equivalence class. By "canonical", I mean that I don't care which representative it is as long as it is the same for all elements of one equivalence class, i.e. I want f x = f y ⟺ (x,y) ∈ R to hold.

What would the best data structure and algorithm for this be in a functional language? I should add that I really need "normal" functional code, i.e. no mutability/state transformer monads.

EDIT: In the mean time, I have come up with this algorithm:

m := empty map
for each s ∈ S do
  if m s = None then
    for each t in {t | (s,t) ∈ R}
      m := m[t ↦ s]

This creates a map that maps any element of S to the representative of its equivalence class, where the representative is the first element that is reached by the iteration over S. I think this actually has linear time (if map operations are constant). However, I am still interested in other solutions, since I don't know how efficient this is in practice.

(my relation is internally represented as a "S → (S Set) option", hence the iteration over {t | (s,t) ∈ R} - this is a cheap operation on that structure.)

like image 602
Manuel Eberl Avatar asked Mar 28 '13 20:03

Manuel Eberl


People also ask

How do you show equivalent equivalence classes?

For each a,b∈A, a∼b if and only if [a]=[b]. Two elements of A are equivalent if and only if their equivalence classes are equal. Any two equivalence classes are either equal or they are disjoint. This means that if two equivalence classes are not disjoint then they must be equal.

How do you write an equivalence class in relations and functions?

We can write this as if a ~ b, b ~ a. It is transitive: Let a, b, and c be elements of X. Then, if a is equivalent to b, and b is equivalent to c, a will also be equivalent to c. We can write this as: for a, b, c in X; if a ~ b and b ~ c it follows that a ~ c.

What is equivalence classes of regular language?

Given any trim DFA D = (Q,Σ,δ,q0,F), the relation ≃D is an equivalence relation which is right-invariant and has finite index. Furthermore, if Q has n states, then the index of ≃D is n, and every equivalence class of ≃D is a regular language.


1 Answers

AFAIK (and a quick search did not disabuse me), there is no known purely-functional equivalent of the conventional disjoint-set datastructure which has comparable asymptotic performance (amortized inverse-Ackermann-function). (the conventional datastructure is not purely-functional because it requires destructive update to perform path compression)

If you are not dead-set on functional purity, you can just use destructive update, and implement the conventional datastructure.

If you don't care about matching asymptotic performance, you can replace the random access array of the conventional datastructure with a persistent associative map, at the expense of an additional O(log N) performance factor, and of needing to verify its correctness.

If you want maximum simplicity for verification purposes, and aren't dead-set on either of the above, you can use an updateable array and drop the union-by-rank optimization. IIRC this yields O(log N) amortized worst-case performance, but may actually improve practical execution speed (as the rank no longer needs to be stored or managed).

like image 68
comingstorm Avatar answered Oct 13 '22 14:10

comingstorm