let intersect (m1 : nfa)
(m2 : nfa)
(p1 : state hashset) : ((state, state list) Hashtbl.t * nfa) =
let m1 = (if !Options.maxsize > 0 && size m1.q > !Options.maxsize then
minimize m1 else m1) in
let m2 = (if !Options.maxsize > 0 && size m2.q > !Options.maxsize then
minimize m2 else m2) in
let lhs = Hashtbl.create (size m2.q * size p1) in
let put tbl x y =
let list = try Hashtbl.find tbl x with Not_found -> [] in
Hashtbl.replace tbl x (y::list) in
let cur_id = ref 0 in
let queue = ref [] in
let newstates = Hashtbl.create (size m1.q) in
let state (x,y) = (try Hashtbl.find newstates (x,y)
with Not_found ->
queue := (x,y)::(!queue);
Hashtbl.replace newstates (x,y) !cur_id;
if Hashset.mem p1 x then put lhs x !cur_id;
incr cur_id;
!cur_id - 1
) in
let result = new_nfa_states (state(m1.s,m2.s)) (state(m1.f,m2.f)) in
let step (q1, q2) =
let delta_step q1' cset1 q2' cset2 =
let charset = Charset.cap cset1 cset2 in
if not (Charset.empty charset) then
add_set_trans result (state (q1,q2)) charset (state (q1',q2'))
in
let left_eps_step m1rhs =
iter (fun m1q2 ->
Hashtbl.iter (fun (a,b) y ->
if a = q1 then
let newstate = state (m1q2, b) in
add_trans result y Epsilon newstate
) newstates
) m1rhs
in
let right_eps_step m2rhs =
iter (fun m2q2 ->
Hashtbl.iter (fun (a,b) y ->
if b = q2 then
let newstate = state (a, m2q2) in
add_trans result y Epsilon newstate
) newstates
) m2rhs
in
let map1 = all_delta ~create:false m1.delta q1 in
let map2 = all_delta ~create:false m2.delta q2 in
let eps1 = which_states ~create:false m1.epsilon q1 in
let eps2 = which_states ~create:false m2.epsilon q2 in
nested_ht_iter map1 map2 delta_step;
left_eps_step eps1;
right_eps_step eps2 in
let rec walk () = match !queue with
| (q1,q2)::qs -> queue := qs; step (q1,q2); walk ()
| _ -> () in
queue := [ m1.s, m2.s ];
walk ();
(lhs, result)