package lrgrep

  1. Overview
  2. Docs
Analyse the stack of a Menhir-generated LR parser using regular expressions

Install

dune-project
 Dependency

Authors

Maintainers

Sources

lrgrep-0.3.tbz
sha256=84a1874d0c063da371e19c84243aac7c40bfcb9aaf204251e0eb0d1f077f2cde
sha512=5a16ff42a196fd741bc64a1bdd45b4dca0098633e73aa665829a44625ec15382891c3643fa210dbe3704336eab095d4024e093e37ae5313810f6754de6119d55

doc/src/lrijkstra_utils/tarjan.ml.html

Source file tarjan.ml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
(******************************************************************************)
(*                                                                            *)
(*                                    Menhir                                  *)
(*                                                                            *)
(*   Copyright Inria. All rights reserved. This file is distributed under     *)
(*   the terms of the GNU General Public License version 2, as described in   *)
(*   the file LICENSE.                                                        *)
(*                                                                            *)
(******************************************************************************)

(* This module provides an implementation of Tarjan's algorithm for
   finding the strongly connected components of a graph.

   The algorithm runs when the functor is applied. Its complexity is
   $O(V+E)$, where $V$ is the number of vertices in the graph $G$, and
   $E$ is the number of edges. *)

module Run (G : sig

  type node

  (* We assume each node has a unique index. Indices must range from
     $0$ to $n-1$, where $n$ is the number of nodes in the graph. *)

  val n: int
  val index: node -> int

  (* Iterating over a node's immediate successors. *)

  val successors: (node -> unit) -> node -> unit

  (* Iterating over all nodes. *)

  val iter: (node -> unit) -> unit

end) = struct

  (* Define the internal data structure associated with each node. *)

  type data = {

      (* Each node carries a flag which tells whether it appears
         within the SCC stack (which is defined below). *)

      mutable stacked: bool;

      (* Each node carries a number. Numbers represent the order in
         which nodes were discovered. *)

      mutable number: int;

      (* Each node [x] records the lowest number associated to a node
         already detected within [x]'s SCC. *)

      mutable low: int;

      (* Each node carries a pointer to a representative element of
         its SCC. This field is used by the algorithm to store its
         results. *)

      mutable representative: G.node;

      (* Each representative node carries a list of the nodes in
         its SCC. This field is used by the algorithm to store its
         results. *)

      mutable scc: G.node list

    }

  (* Define a mapping from external nodes to internal ones. Here, we
     simply use each node's index as an entry into a global array. *)

  let table =

    (* Create the array. We initially fill it with [None], of type
       [data option], because we have no meaningful initial value of
       type [data] at hand. *)

    let table = Array.make G.n None in

    (* Initialize the array. *)

    G.iter (fun x ->
      table.(G.index x) <- Some {
        stacked = false;
        number = 0;
        low = 0;
        representative = x;
        scc = []
      }
    );

    (* Define a function which gives easy access to the array. It maps
       each node to its associated piece of internal data. *)

    function x ->
      match table.(G.index x) with
      | Some dx ->
          dx
      | None ->
          assert false (* Indices do not cover the range $0\ldots n$, as expected. *)

  (* Create an empty stack, used to record all nodes which belong to
     the current SCC. *)

  let scc_stack = Stack.create()

  (* Initialize a function which allocates numbers for (internal)
     nodes. A new number is assigned to each node the first time it is
     visited. Numbers returned by this function start at 1 and
     increase. Initially, all nodes have number 0, so they are
     considered unvisited. *)

  let mark =
    let counter = ref 0 in
    fun dx ->
      incr counter;
      dx.number <- !counter;
      dx.low <- !counter

  (* This reference will hold a list of all representative nodes.
     The components that have been identified last appear at the
     head of the list. *)

  let representatives =
    ref []

  (* Look at all nodes of the graph, one after the other. Any
     unvisited nodes become roots of the search forest. *)

  let () = G.iter (fun root ->
    let droot = table root in

    if droot.number = 0 then begin

      (* This node hasn't been visited yet. Start a depth-first walk
         from it. *)

      mark droot;
      droot.stacked <- true;
      Stack.push droot scc_stack;

      let rec walk x =
        let dx = table x in

        G.successors (fun y ->
          let dy = table y in

          if dy.number = 0 then begin

            (* $y$ hasn't been visited yet, so $(x,y)$ is a regular
               edge, part of the search forest. *)

            mark dy;
            dy.stacked <- true;
            Stack.push dy scc_stack;

            (* Continue walking, depth-first. *)

            walk y;
            if dy.low < dx.low then
              dx.low <- dy.low

          end
          else if (dy.low < dx.low) && dy.stacked then begin

            (* The first condition above indicates that $y$ has been
               visited before $x$, so $(x, y)$ is a backwards or
               transverse edge. The second condition indicates that
               $y$ is inside the same SCC as $x$; indeed, if it
               belongs to another SCC, then the latter has already
               been identified and moved out of [scc_stack]. *)

            if dy.number < dx.low then
              dx.low <- dy.number

          end

        ) x;

        (* We are done visiting $x$'s neighbors. *)

        if dx.low = dx.number then begin

          (* $x$ is the entry point of a SCC. The whole SCC is now
             available; move it out of the stack. We pop elements out
             of the SCC stack until $x$ itself is found. *)

          let rec loop () =
            let element = Stack.pop scc_stack in
            element.stacked <- false;
            dx.scc <- element.representative :: dx.scc;
            element.representative <- x;
            if element != dx then
              loop() in

          loop();
          representatives := x :: !representatives

        end in

      walk root

    end
  )

  (* There only remains to make our results accessible to the outside. *)

  let representative x =
    (table x).representative

  let scc x =
    (table x).scc

  let representatives =
    Array.of_list !representatives

  (* The array [representatives] contains a representative for each component.
     The components that have been identified last appear first in this array.
     A component is identified only after its successors have been identified;
     therefore, this array is naturally in topological order. *)

  let yield action x =
      let data = table x in
      assert (data.representative == x); (* a sanity check *)
      assert (data.scc <> []);           (* a sanity check *)
      action x data.scc

  let iter action =
    Array.iter (yield action) representatives

  let rev_topological_iter action =
    for i = Array.length representatives - 1 downto 0 do
      yield action representatives.(i)
    done

  let map action =
    Array.map (yield action) representatives |> Array.to_list

  let rev_map action =
    let accu = ref [] in
    rev_topological_iter (fun repr labels ->
      accu := action repr labels :: !accu
    );
    !accu

end

open Fix.Indexing

module type SCC = sig
  type node
  type n
  val n : n cardinal
  val representatives : (n, node index) vector
  val nodes : (n, node Utils.IndexSet.t) vector
  val component : (node, n index) vector
end

module IndexedSCC (G : sig
  include CARDINAL
  val successors : (n index -> unit) -> n index -> unit
end) = struct
  module SCC = Run (struct
    type node = G.n index
    let n = cardinal G.n
    let index n = (n : _ index :> int)
    let successors = G.successors
    let iter f = Index.iter G.n f
  end)

  module Repr = Vector.Of_array(struct
      type a = G.n index
      let array = SCC.representatives
    end)

  type node = G.n
  type n = Repr.n
  let n = Vector.length Repr.vector

  let representatives = Repr.vector

  let nodes = Vector.map
      (fun node -> Utils.IndexSet.of_list (SCC.scc node))
      representatives

  let component = Vector.make' G.n (fun () -> Index.of_int n 0)

  let () =
    Vector.iteri (fun scc nodes' ->
        Utils.IndexSet.iter
          (fun node -> Vector.set component node scc)
          nodes'
      ) nodes
end

open Utils
open Misc

type 'n scc = (module SCC with type node = 'n)

let indexed_scc (type n) (n : n cardinal) ~succ : n scc =
  let module Scc = IndexedSCC(struct
      type nonrec n = n
      let n = n
      let successors = succ
    end)
  in
  (module Scc)

let indexset_bind : 'a indexset -> ('a index -> 'b indexset) -> 'b indexset =
  fun s f ->
  IndexSet.fold_right (fun acc lr1 -> IndexSet.union (f lr1) acc) IndexSet.empty s

let close_forward (type a n)
    ((module Scc) : n scc)
    ~(succ:(n index -> unit) -> n index -> unit)
    (rel: (n, a indexset) vector)
  =
  Vector.rev_iteri begin fun _scc nodes ->
    let sccs = ref IndexSet.empty in
    IndexSet.rev_iter begin fun i ->
      succ (fun j -> sccs := IndexSet.add Scc.component.:(j) !sccs) i
    end nodes;
    let sccs = !sccs in
    let set = indexset_bind sccs (fun scc -> rel.:(Scc.representatives.:(scc))) in
    let set = IndexSet.union (indexset_bind nodes (Vector.get rel)) set in
    IndexSet.iter (fun i -> rel.:(i) <- set) nodes
  end Scc.nodes

let close_backward (type a n)
    ((module Scc) : n scc)
    ~(pred:(n index -> unit) -> n index -> unit)
    (rel: (n, a indexset) vector)
  =
  Vector.iteri begin fun _scc nodes ->
    let sccs = ref IndexSet.empty in
    IndexSet.rev_iter begin fun i ->
      pred (fun j -> sccs := IndexSet.add Scc.component.:(j) !sccs) i
    end nodes;
    let sccs = !sccs in
    let set = indexset_bind sccs (fun scc -> rel.:(Scc.representatives.:(scc))) in
    let set = IndexSet.union (indexset_bind nodes (Vector.get rel)) set in
    IndexSet.iter (fun i -> rel.:(i) <- set) nodes
  end Scc.nodes

let close_relation
    (type n a)
    (succ : (n index -> unit) -> n index -> unit)
    (rel : (n, a indexset) vector)
  =
  close_forward (indexed_scc (Vector.length rel) ~succ) ~succ rel