Iterate over subtrees grouped by relative paths in breadth-first order. `group_subtrees` allows for applying operations over all nodes of a collection of DataTree objects with nodes matched by their relative paths. Example usage:: outputs = {} for path, (node_a, node_b
(
*trees: AnyNamedNode,
)
| 801 | |
| 802 | |
| 803 | def group_subtrees( |
| 804 | *trees: AnyNamedNode, |
| 805 | ) -> Iterator[tuple[str, tuple[AnyNamedNode, ...]]]: |
| 806 | """Iterate over subtrees grouped by relative paths in breadth-first order. |
| 807 | |
| 808 | `group_subtrees` allows for applying operations over all nodes of a |
| 809 | collection of DataTree objects with nodes matched by their relative paths. |
| 810 | |
| 811 | Example usage:: |
| 812 | |
| 813 | outputs = {} |
| 814 | for path, (node_a, node_b) in group_subtrees(tree_a, tree_b): |
| 815 | outputs[path] = f(node_a, node_b) |
| 816 | tree_out = DataTree.from_dict(outputs) |
| 817 | |
| 818 | Parameters |
| 819 | ---------- |
| 820 | *trees : Tree |
| 821 | Trees to iterate over. |
| 822 | |
| 823 | Yields |
| 824 | ------ |
| 825 | A tuple of the relative path and corresponding nodes for each subtree in the |
| 826 | inputs. |
| 827 | |
| 828 | Raises |
| 829 | ------ |
| 830 | TreeIsomorphismError |
| 831 | If trees are not isomorphic, i.e., they have different structures. |
| 832 | |
| 833 | See Also |
| 834 | -------- |
| 835 | DataTree.subtree |
| 836 | DataTree.subtree_with_keys |
| 837 | """ |
| 838 | if not trees: |
| 839 | raise TypeError("must pass at least one tree object") |
| 840 | |
| 841 | # https://en.wikipedia.org/wiki/Breadth-first_search#Pseudocode |
| 842 | queue = collections.deque([(NodePath(), trees)]) |
| 843 | |
| 844 | while queue: |
| 845 | path, active_nodes = queue.popleft() |
| 846 | |
| 847 | # yield before raising an error, in case the caller chooses to exit |
| 848 | # iteration early |
| 849 | yield str(path), active_nodes |
| 850 | |
| 851 | first_node = active_nodes[0] |
| 852 | if any( |
| 853 | sibling.children.keys() != first_node.children.keys() |
| 854 | for sibling in active_nodes[1:] |
| 855 | ): |
| 856 | path_str = "root node" if not path.parts else f"node {str(path)!r}" |
| 857 | child_summary = " vs ".join( |
| 858 | str(list(node.children)) for node in active_nodes |
| 859 | ) |
| 860 | raise TreeIsomorphismError( |
searching dependent graphs…