docs: def tree_to_gexf(tree:'BubbleTree') -> str:
      """Compute the gexf representation of given power graph,
      and push it into given file.
  
      See https://gephi.org/gexf/format/index.html
      for format doc.
  
      """
      output_nodes, output_edges = '', ''
  
      def build_node(node:str) -> str:
          """Yield strings describing given node, recursively"""
          if tree.inclusions[node]:  # it's a powernode
              yield '<node id="{}" label="{}">'.format(node, node)
              yield '<nodes>'
              for sub in tree.inclusions[node]:
                  yield from build_node(sub)
              yield '</nodes>'
              yield '</node>'
          else:  # it's a regular node
              yield '<node id="{}" label="{}"/>'.format(node, node)
          return
  
      # build full hierarchy from the roots
      output_nodes += '\n'.join('\n'.join(build_node(root)) for root in tree.roots)
  
      # # add the edges to the final graph
      for idx, (source, targets) in enumerate(tree.edges.items()):
          for target in targets:
              if source <= target:  # edges dict is complete. This avoid multiple edges.
                  output_edges += '<edge id="{}" source="{}" target="{}" />\n'.format(idx, source, target)
  
      return GEXF_TEMPLATE.format(
          'directed' if tree.oriented else 'undirected',
          output_nodes,
          output_edges
      )