(*
    HLins: insert http-links into HTML documents.
    See http://www.lri.fr/~treinen/hlins

    Copyright (C) 1999 Ralf Treinen <treinen@lri.fr>

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

*)


(***************************************************************************)
(*  Module defining the type "automaton" for multi-string search           *)
(***************************************************************************)


(*
   Data type "automaton" used for multi-string matching à la Morris - Pratt.

   See Chapter 7.1 in Crochemore & Rytter, Text Algorithms, Oxford
   University Press, 1994.
*)

(* Type of the transition tables of a single state. An element of type
   transitions is a partial mapping from characters to integers.
*)
type transitions;;

(* create an empty transition table *)
val empty_transitions : transitions;;

(* (get_transition t c) returns the result of the transition t under
   character c. Raises Not_found if the transition is not defined.
*)
val get_transition : transitions -> char -> int;;

(* (add_transition t c p) yields the transition t plus c -> p *)
val add_transition : transitions ->  char -> int -> transitions;;

(* fold function on transitions: let the transition function t be
   [c1 -> q1; ... ; cn -> qn] (where this could have been in any order). 
   Then (transitions_fold f i t) yields
   f ( ... (f (f i c1 q1) c2 q2) ... ) cn qn
*)
val transitions_fold :
  ('a -> char -> int -> 'a) -> 'a -> transitions -> 'a;;

type automaton = {
  max_path_length:   int;
  number_of_states:  int;
  tree:              transitions array;
  level:             int array;               
  board:             int array;
  suf:               int array;
  found:             (int list) array;
  expand:            (int list) array
};;                     

(*

   First some terminology:
   - a word x is a prefix of a word y if exists z with y = x^z
   -               suffix             if exists z with y = z^x
   -               factor             if exists z1,z2 with y = z1^x^z2
   A prefix (resp. suffix) is proper if z is not empty.

   When building the automaton we are given an array W of length L of
   non-empty words. Furthermore, there is some notion of an
   abbreviation of a word. Let V be the set consisting of the elements
   of W plus all their abbreviations.  Let N be the cardinality of the
   prefix-closure of V. We call "nodes" the numbers n with
   0<=n<N. max_path_length is  the maximal length of a word in W.

   The size of the arrays f is at least N = number_of_states.

   The array tree defines a graph where a directed edge labeled with
   character c goes from node n to node m iff (c,m) in n. We require
   that 
   - the graph is a tree.
   - for any node n and character c there is at most one node m with
     (c,m) in tree.(n).
   Hence, the graph is in fact a feature tree.
   For any node n, let path(n) be the word of characters on the edges
   from the root to the node n. We require that
   - path(0) = the empty word
   - the set of all pathes in the tree = V

   We require that for any node n that
   - level.(n) is the length of path(n).
   - board.(0) = -1
   - if n >= 1: board(n) is the node m such that path(m) is the
     longest proper suffix of path(n) that is a prefix of a word in V.
   - suf.(n) is the node m such that path(m) is the longest (not
     necessarily proper) suffix of path(n) that is a word in V.
     suf.(n) = 0 if such a m does not exist.
   
   Furthermore, we require for all nodes n that
   - found.(n) = list of indices in W of path(n)
   - expand.(n) = list of all indices of words w in W such that
     path(n) is an abbreviation of w.

  Hence, we have the following equivalence:
           suf(n) = n
       iff path(n) is a word in V
       iff found.(n) @ expand.(n) <> nil.

*)








