(**************************************************************************)
(*                                                                        *)
(*  Copyright (C) Jean-Christophe Filliatre                               *)
(*                                                                        *)
(*  This software is free software; you can redistribute it and/or        *)
(*  modify it under the terms of the GNU Library General Public           *)
(*  License version 2.1, with the special exception on linking            *)
(*  described in file LICENSE.                                            *)
(*                                                                        *)
(*  This software 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.                  *)
(*                                                                        *)
(**************************************************************************)

(* Persistent union-find = Tarjan's algorithm with persistent arrays *)

(* persistent arrays; see the module [Parray] for explanations *)
module Pa = struct

  type t = data ref
  and data =
    | Array of int array 
    | Diff of int * int * t
        
  let create n v = ref (Array (Array.create n v))
  let init n f = ref (Array (Array.init n f))
    
  (* reroot t ensures that t becomes an Array node *)
  let rec reroot t = match !t with
    | Array _ -> ()
    | Diff (i, v, t') -> 
        reroot t';
        begin match !t' with
          | Array a as n ->
              let v' = a.(i) in
              a.(i) <- v;
              t := n;
              t' := Diff (i, v', t)
          | Diff _ -> assert false
        end
  
  let rec rerootk t k = match !t with
    | Array _ -> k ()
    | Diff (i, v, t') -> 
        rerootk t' (fun () -> begin match !t' with
                      | Array a as n ->
                          let v' = a.(i) in
                          a.(i) <- v;
                          t := n;
                          t' := Diff (i, v', t)
                      | Diff _ -> assert false end; k())

  let reroot t = rerootk t (fun () -> ())

  let rec get t i = match !t with
    | Array a -> 
        a.(i)
    | Diff _ -> 
        reroot t; 
        begin match !t with Array a -> a.(i) | Diff _ -> assert false end
      
  let set t i v = 
    reroot t;
    match !t with
      | Array a as n ->
          let old = a.(i) in
          if old == v then
            t
          else begin
            a.(i) <- v;
            let res = ref n in
            t := Diff (i, old, res);
            res
          end
      | Diff _ ->
          assert false

end

(* Tarjan's algorithm *)

type t = { 
  mutable father: Pa.t; (* mutable to allow path compression *)
  c: Pa.t; (* ranks *)
}
      
let create n = 
  { c = Pa.create n 0;
    father = Pa.init n (fun i -> i) }
    
let rec find_aux f i = 
  let fi = Pa.get f i in
  if fi == i then 
    f, i
  else 
    let f, r = find_aux f fi in 
    let f = Pa.set f i r in
    f, r
      
let find h x = 
  let f,rx = find_aux h.father x in h.father <- f; rx
  
let union h x y = 
  let rx = find h x in
  let ry = find h y in
  if rx != ry then begin
    let rxc = Pa.get h.c rx in
    let ryc = Pa.get h.c ry in
    if rxc > ryc then
      { h with father = Pa.set h.father ry rx }
    else if rxc < ryc then
      { h with father = Pa.set h.father rx ry }
    else
      { c = Pa.set h.c rx (rxc + 1);
        father = Pa.set h.father ry rx }
  end else
    h


(* tests *)
(***
let t = create 10
let () = assert (find t 0 <> find t 1)
let t = union t 0 1
let () = assert (find t 0 = find t 1)
let () = assert (find t 0 <> find t 2)
let t = union t 2 3 
let t = union t 0 3
let () = assert (find t 1 = find t 2)
let t = union t 4 4
let () = assert (find t 4 <> find t 3)
***)



This document was generated using caml2html