let solve_group (graph : graph)
(group : string hashset)
(inbound : string hashset) : graph list =
let is_top_node id =
let id_node = find_node graph id in
let edge_from_group edge = match edge with
| InConcat (a,b) -> mem group a || mem group b
| InIsect (a) -> mem group a
in
not (exists edge_from_group id_node.inb) in
let group_copy = copy group in
let visited = create (Hashtbl.length group) in
let visit x = add visited x; remove group x in
let visited x = mem visited x in
let eliminate_top id =
let id_node = find_node graph id in
let perform_intersect edge = match edge with
| InIsect source -> group_intersect graph source id
| _ -> () in
let perform_concat edge = match edge with
| OutConcatRight(lhs, target) when visited lhs ->
group_concat graph lhs id target
| OutConcatLeft(rhs, target) when visited rhs ->
group_concat graph id rhs target
| _ -> ()
in
iter perform_intersect id_node.inb;
iter perform_concat id_node.outb;
visit id in
let rec walk () =
let topnodes = filter (fun x ->
is_top_node x && not (visited x)
) group in
List.iter eliminate_top topnodes;
if Hashtbl.length group = 0 then ()
else walk () in
let _ = walk () in
let solutions = enumerate_solutions group_copy graph in
let solutions = filter_solutions group_copy solutions in
fix_edges group_copy inbound graph;
List.iter (fix_edges group_copy inbound) solutions;
solutions