docs: def copy_and_disconnect_tree(root, machine):
      """Copy a RoutingTree (containing nothing but RoutingTrees), disconnecting
      nodes which are not connected in the machine.
  
      Note that if a dead chip is part of the input RoutingTree, no corresponding
      node will be included in the copy. The assumption behind this is that the
      only reason a tree would visit a dead chip is because a route passed
      through the chip and wasn't actually destined to arrive at that chip. This
      situation is impossible to confirm since the input routing trees have not
      yet been populated with vertices. The caller is responsible for being
      sensible.
  
      Parameters
      ----------
      root : :py:class:`~rig.place_and_route.routing_tree.RoutingTree`
          The root of the RoutingTree that contains nothing but RoutingTrees
          (i.e. no children which are vertices or links).
      machine : :py:class:`~rig.place_and_route.Machine`
          The machine in which the routes exist.
  
      Returns
      -------
      (root, lookup, broken_links)
          Where:
          * `root` is the new root of the tree
            :py:class:`~rig.place_and_route.routing_tree.RoutingTree`
          * `lookup` is a dict {(x, y):
            :py:class:`~rig.place_and_route.routing_tree.RoutingTree`, ...}
          * `broken_links` is a set ([(parent, child), ...]) containing all
            disconnected parent and child (x, y) pairs due to broken links.
      """
      new_root = None
  
      # Lookup for copied routing tree {(x, y): RoutingTree, ...}
      new_lookup = {}
  
      # List of missing connections in the copied routing tree [(new_parent,
      # new_child), ...]
      broken_links = set()
  
      # A queue [(new_parent, direction, old_node), ...]
      to_visit = deque([(None, None, root)])
      while to_visit:
          new_parent, direction, old_node = to_visit.popleft()
  
          if old_node.chip in machine:
              # Create a copy of the node
              new_node = RoutingTree(old_node.chip)
              new_lookup[new_node.chip] = new_node
          else:
              # This chip is dead, move all its children into the parent node
              assert new_parent is not None, \
                  "Net cannot be sourced from a dead chip."
              new_node = new_parent
  
          if new_parent is None:
              # This is the root node
              new_root = new_node
          elif new_node is not new_parent:
              # If this node is not dead, check connectivity to parent node (no
              # reason to check connectivity between a dead node and its parent).
              if direction in links_between(new_parent.chip,
                                            new_node.chip,
                                            machine):
                  # Is connected via working link
                  new_parent.children.append((direction, new_node))
              else:
                  # Link to parent is dead (or original parent was dead and the
                  # new parent is not adjacent)
                  broken_links.add((new_parent.chip, new_node.chip))
  
          # Copy children
          for child_direction, child in old_node.children:
              to_visit.append((new_node, child_direction, child))
  
      return (new_root, new_lookup, broken_links)