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