let concat (a  : nfa)
           (b  : nfa)  
           (p1 : state hashset) 
           (p2 : state hashset) : ((state, state) Hashtbl.t * 
                                 (state, state) Hashtbl.t * nfa) =
  let offset = a.next_q in
  let convert x = x + offset in
  let lhs = fmap p1 (fun x -> x) in
  let rhs = fmap p2 convert in
  let q = copy a.q in
  let _ = iter (fun m2q -> add q (convert m2q)) b.q in
  let delta = Hashtbl.create (Hashtbl.length a.delta + Hashtbl.length b.delta) in
  let _ = copy_table a.delta delta (fun x -> x) in
  let _ = copy_table b.delta delta convert in
  let epsilon = Hashtbl.create (Hashtbl.length a.delta + Hashtbl.length b.delta) in
  let _ = copy_table a.epsilon epsilon (fun x -> x) in
  let _ = copy_table b.epsilon epsilon convert in
  let result = { s = a.s; f = (convert b.f); delta = delta; epsilon = epsilon; q = q;
                 next_q = a.next_q + b.next_q } in
  let curset = which_states epsilon a.f in
  let _ = add curset (convert b.s) in
    (lhs, rhs, result)