~ubuntu-branches/ubuntu/trusty/menhir/trusty

« back to all changes in this revision

Viewing changes to unionFind.ml

  • Committer: Bazaar Package Importer
  • Author(s): Mehdi Dogguy
  • Date: 2009-02-22 23:41:17 UTC
  • mfrom: (1.1.5 upstream) (2.1.2 squeeze)
  • Revision ID: james.westby@ubuntu.com-20090222234117-yxk115kvzv634utx
Tags: 20090204.dfsg-2
* New binary package libmenhir-ocaml-dev, Closes: #516134.
* Use dh-ocaml predefined variables.
* Use predefined variable OCAML_BEST (dh-ocaml >= 0.4).
* debian/svn-deblayout: remove no longer needed SVN setting

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
(**************************************************************************)
2
 
(*                                                                        *)
3
 
(*  Menhir                                                                *)
4
 
(*                                                                        *)
5
 
(*  Fran�ois Pottier and Yann R�gis-Gianas, INRIA Rocquencourt            *)
6
 
(*                                                                        *)
7
 
(*  Copyright 2005 Institut National de Recherche en Informatique et      *)
8
 
(*  en Automatique. All rights reserved. This file is distributed         *)
9
 
(*  under the terms of the Q Public License version 1.0, with the         *)
10
 
(*  change described in file LICENSE.                                     *)
11
 
(*                                                                        *)
12
 
(**************************************************************************)
13
 
 
14
 
(* $Id: unionFind.ml,v 1.5 2005/12/01 16:20:07 regisgia Exp $ *)
15
 
 
16
 
(** This module implements a simple and efficient union/find algorithm.
17
 
    See Robert E. Tarjan, ``Efficiency of a Good But Not Linear Set
18
 
    Union Algorithm'', JACM 22(2), 1975. *)
19
 
 
20
 
(** The abstraction defined by this module is a set of points,
21
 
    partitioned into equivalence classes. With each equivalence class,
22
 
    a piece of information, of abstract type ['a], is associated; we
23
 
    call it a descriptor.
24
 
 
25
 
    A point is implemented as a cell, whose (mutable) contents consist
26
 
    of a single link to either information about the equivalence class,
27
 
    or another point. Thus, points form a graph, which must be acyclic,
28
 
    and whose connected components are the equivalence classes. In
29
 
    every equivalence class, exactly one point has no outgoing edge,
30
 
    and carries information about the class instead. It is the class's
31
 
    representative element.
32
 
 
33
 
    Information about a class consists of an integer weight (the number
34
 
    of elements in the class) and of the class's descriptor. *)
35
 
type 'a point = {
36
 
    mutable link: 'a link
37
 
  } 
38
 
 
39
 
and 'a link =
40
 
  | Info of 'a info
41
 
  | Link of 'a point
42
 
 
43
 
and 'a info = {
44
 
    mutable weight: int;
45
 
    mutable descriptor: 'a
46
 
  } 
47
 
 
48
 
(** [fresh desc] creates a fresh point and returns it. It forms an
49
 
    equivalence class of its own, whose descriptor is [desc]. *)
50
 
let fresh desc = {
51
 
  link = Info { weight = 1; descriptor = desc }
52
 
53
 
 
54
 
(** [repr point] returns the representative element of [point]'s
55
 
    equivalence class. It is found by starting at [point] and following
56
 
    the links. For efficiency, the function performs path compression
57
 
    at the same time. *)
58
 
let rec repr point =
59
 
  match point.link with
60
 
  | Link point' ->
61
 
      let point'' = repr point' in
62
 
      if point'' != point' then
63
 
 
64
 
        (* [point''] is [point']'s representative element. Because we
65
 
           just invoked [repr point'], [point'.link] must be [Link
66
 
           point'']. We write this value into [point.link], thus
67
 
           performing path compression. Note that this function never
68
 
           performs memory allocation. *)
69
 
 
70
 
        point.link <- point'.link;
71
 
      point''
72
 
  | Info _ ->
73
 
      point
74
 
 
75
 
(** [find point] returns the descriptor associated with [point]'s
76
 
    equivalence class. *)
77
 
let rec find point =
78
 
 
79
 
  (* By not calling [repr] immediately, we optimize the common cases
80
 
     where the path starting at [point] has length 0 or 1, at the
81
 
     expense of the general case. *)
82
 
 
83
 
  match point.link with
84
 
  | Info info
85
 
  | Link { link = Info info } ->
86
 
      info.descriptor
87
 
  | Link { link = Link _ } ->
88
 
      find (repr point)
89
 
 
90
 
let rec change point v = 
91
 
  match point.link with
92
 
  | Info info
93
 
  | Link { link = Info info } ->
94
 
      info.descriptor <- v
95
 
  | Link { link = Link _ } ->
96
 
      change (repr point) v
97
 
 
98
 
(** [union point1 point2] merges the equivalence classes associated
99
 
    with [point1] and [point2] (which must be distinct) into a single
100
 
    class whose descriptor is that originally associated with [point2].
101
 
 
102
 
    The fact that [point1] and [point2] do not originally belong to the
103
 
    same class guarantees that we do not create a cycle in the graph.
104
 
 
105
 
    The weights are used to determine whether [point1] should be made
106
 
    to point to [point2], or vice-versa. By making the representative
107
 
    of the smaller class point to that of the larger class, we
108
 
    guarantee that paths remain of logarithmic length (not accounting
109
 
    for path compression, which makes them yet smaller). *)
110
 
let union point1 point2 =
111
 
  let point1 = repr point1
112
 
  and point2 = repr point2 in
113
 
  assert (point1 != point2);
114
 
  match point1.link, point2.link with
115
 
  | Info info1, Info info2 ->
116
 
      let weight1 = info1.weight
117
 
      and weight2 = info2.weight in
118
 
      if weight1 >= weight2 then begin
119
 
        point2.link <- Link point1;
120
 
        info1.weight <- weight1 + weight2;
121
 
        info1.descriptor <- info2.descriptor
122
 
      end
123
 
      else begin
124
 
        point1.link <- Link point2;
125
 
        info2.weight <- weight1 + weight2
126
 
      end
127
 
  | _, _ ->
128
 
      assert false (* [repr] guarantees that [link] matches [Info _]. *)
129
 
 
130
 
(** [equivalent point1 point2] tells whether [point1] and [point2]
131
 
    belong to the same equivalence class. *)
132
 
let equivalent point1 point2 =
133
 
  repr point1 == repr point2
134
 
 
135
 
(** [eunion point1 point2] is identical to [union], except it does
136
 
    nothing if [point1] and [point2] are already equivalent. *)
137
 
let eunion point1 point2 =
138
 
  if not (equivalent point1 point2) then
139
 
    union point1 point2
140
 
 
141
 
(** [redundant] maps all members of an equivalence class, but one, to
142
 
    [true]. *)
143
 
let redundant = function
144
 
  | { link = Link _ } ->
145
 
      true
146
 
  | { link = Info _ } ->
147
 
      false
148