aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py
diff options
context:
space:
mode:
authorS. Solomon Darnell2025-03-28 21:52:21 -0500
committerS. Solomon Darnell2025-03-28 21:52:21 -0500
commit4a52a71956a8d46fcb7294ac71734504bb09bcc2 (patch)
treeee3dc5af3b6313e921cd920906356f5d4febc4ed /.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py
parentcc961e04ba734dd72309fb548a2f97d67d578813 (diff)
downloadgn-ai-master.tar.gz
two version of R2R are hereHEADmaster
Diffstat (limited to '.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py321
1 files changed, 321 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py
new file mode 100644
index 00000000..549d335d
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/operators/all.py
@@ -0,0 +1,321 @@
+"""Operations on many graphs."""
+
+from itertools import chain, repeat
+
+import networkx as nx
+
+__all__ = ["union_all", "compose_all", "disjoint_union_all", "intersection_all"]
+
+
+@nx._dispatchable(graphs="[graphs]", preserve_all_attrs=True, returns_graph=True)
+def union_all(graphs, rename=()):
+ """Returns the union of all graphs.
+
+ The graphs must be disjoint, otherwise an exception is raised.
+
+ Parameters
+ ----------
+ graphs : iterable
+ Iterable of NetworkX graphs
+
+ rename : iterable , optional
+ Node names of graphs can be changed by specifying the tuple
+ rename=('G-','H-') (for example). Node "u" in G is then renamed
+ "G-u" and "v" in H is renamed "H-v". Infinite generators (like itertools.count)
+ are also supported.
+
+ Returns
+ -------
+ U : a graph with the same type as the first graph in list
+
+ Raises
+ ------
+ ValueError
+ If `graphs` is an empty list.
+
+ NetworkXError
+ In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.
+
+ Notes
+ -----
+ For operating on mixed type graphs, they should be converted to the same type.
+ >>> G = nx.Graph()
+ >>> H = nx.DiGraph()
+ >>> GH = union_all([nx.DiGraph(G), H])
+
+ To force a disjoint union with node relabeling, use
+ disjoint_union_all(G,H) or convert_node_labels_to integers().
+
+ Graph, edge, and node attributes are propagated to the union graph.
+ If a graph attribute is present in multiple graphs, then the value
+ from the last graph in the list with that attribute is used.
+
+ Examples
+ --------
+ >>> G1 = nx.Graph([(1, 2), (2, 3)])
+ >>> G2 = nx.Graph([(4, 5), (5, 6)])
+ >>> result_graph = nx.union_all([G1, G2])
+ >>> result_graph.nodes()
+ NodeView((1, 2, 3, 4, 5, 6))
+ >>> result_graph.edges()
+ EdgeView([(1, 2), (2, 3), (4, 5), (5, 6)])
+
+ See Also
+ --------
+ union
+ disjoint_union_all
+ """
+ R = None
+ seen_nodes = set()
+
+ # rename graph to obtain disjoint node labels
+ def add_prefix(graph, prefix):
+ if prefix is None:
+ return graph
+
+ def label(x):
+ return f"{prefix}{x}"
+
+ return nx.relabel_nodes(graph, label)
+
+ rename = chain(rename, repeat(None))
+ graphs = (add_prefix(G, name) for G, name in zip(graphs, rename))
+
+ for i, G in enumerate(graphs):
+ G_nodes_set = set(G.nodes)
+ if i == 0:
+ # Union is the same type as first graph
+ R = G.__class__()
+ elif G.is_directed() != R.is_directed():
+ raise nx.NetworkXError("All graphs must be directed or undirected.")
+ elif G.is_multigraph() != R.is_multigraph():
+ raise nx.NetworkXError("All graphs must be graphs or multigraphs.")
+ elif not seen_nodes.isdisjoint(G_nodes_set):
+ raise nx.NetworkXError(
+ "The node sets of the graphs are not disjoint.\n"
+ "Use `rename` to specify prefixes for the graphs or use\n"
+ "disjoint_union(G1, G2, ..., GN)."
+ )
+
+ seen_nodes |= G_nodes_set
+ R.graph.update(G.graph)
+ R.add_nodes_from(G.nodes(data=True))
+ R.add_edges_from(
+ G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True)
+ )
+
+ if R is None:
+ raise ValueError("cannot apply union_all to an empty list")
+
+ return R
+
+
+@nx._dispatchable(graphs="[graphs]", preserve_all_attrs=True, returns_graph=True)
+def disjoint_union_all(graphs):
+ """Returns the disjoint union of all graphs.
+
+ This operation forces distinct integer node labels starting with 0
+ for the first graph in the list and numbering consecutively.
+
+ Parameters
+ ----------
+ graphs : iterable
+ Iterable of NetworkX graphs
+
+ Returns
+ -------
+ U : A graph with the same type as the first graph in list
+
+ Raises
+ ------
+ ValueError
+ If `graphs` is an empty list.
+
+ NetworkXError
+ In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.
+
+ Examples
+ --------
+ >>> G1 = nx.Graph([(1, 2), (2, 3)])
+ >>> G2 = nx.Graph([(4, 5), (5, 6)])
+ >>> U = nx.disjoint_union_all([G1, G2])
+ >>> list(U.nodes())
+ [0, 1, 2, 3, 4, 5]
+ >>> list(U.edges())
+ [(0, 1), (1, 2), (3, 4), (4, 5)]
+
+ Notes
+ -----
+ For operating on mixed type graphs, they should be converted to the same type.
+
+ Graph, edge, and node attributes are propagated to the union graph.
+ If a graph attribute is present in multiple graphs, then the value
+ from the last graph in the list with that attribute is used.
+ """
+
+ def yield_relabeled(graphs):
+ first_label = 0
+ for G in graphs:
+ yield nx.convert_node_labels_to_integers(G, first_label=first_label)
+ first_label += len(G)
+
+ R = union_all(yield_relabeled(graphs))
+
+ return R
+
+
+@nx._dispatchable(graphs="[graphs]", preserve_all_attrs=True, returns_graph=True)
+def compose_all(graphs):
+ """Returns the composition of all graphs.
+
+ Composition is the simple union of the node sets and edge sets.
+ The node sets of the supplied graphs need not be disjoint.
+
+ Parameters
+ ----------
+ graphs : iterable
+ Iterable of NetworkX graphs
+
+ Returns
+ -------
+ C : A graph with the same type as the first graph in list
+
+ Raises
+ ------
+ ValueError
+ If `graphs` is an empty list.
+
+ NetworkXError
+ In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.
+
+ Examples
+ --------
+ >>> G1 = nx.Graph([(1, 2), (2, 3)])
+ >>> G2 = nx.Graph([(3, 4), (5, 6)])
+ >>> C = nx.compose_all([G1, G2])
+ >>> list(C.nodes())
+ [1, 2, 3, 4, 5, 6]
+ >>> list(C.edges())
+ [(1, 2), (2, 3), (3, 4), (5, 6)]
+
+ Notes
+ -----
+ For operating on mixed type graphs, they should be converted to the same type.
+
+ Graph, edge, and node attributes are propagated to the union graph.
+ If a graph attribute is present in multiple graphs, then the value
+ from the last graph in the list with that attribute is used.
+ """
+ R = None
+
+ # add graph attributes, H attributes take precedent over G attributes
+ for i, G in enumerate(graphs):
+ if i == 0:
+ # create new graph
+ R = G.__class__()
+ elif G.is_directed() != R.is_directed():
+ raise nx.NetworkXError("All graphs must be directed or undirected.")
+ elif G.is_multigraph() != R.is_multigraph():
+ raise nx.NetworkXError("All graphs must be graphs or multigraphs.")
+
+ R.graph.update(G.graph)
+ R.add_nodes_from(G.nodes(data=True))
+ R.add_edges_from(
+ G.edges(keys=True, data=True) if G.is_multigraph() else G.edges(data=True)
+ )
+
+ if R is None:
+ raise ValueError("cannot apply compose_all to an empty list")
+
+ return R
+
+
+@nx._dispatchable(graphs="[graphs]", returns_graph=True)
+def intersection_all(graphs):
+ """Returns a new graph that contains only the nodes and the edges that exist in
+ all graphs.
+
+ Parameters
+ ----------
+ graphs : iterable
+ Iterable of NetworkX graphs
+
+ Returns
+ -------
+ R : A new graph with the same type as the first graph in list
+
+ Raises
+ ------
+ ValueError
+ If `graphs` is an empty list.
+
+ NetworkXError
+ In case of mixed type graphs, like MultiGraph and Graph, or directed and undirected graphs.
+
+ Notes
+ -----
+ For operating on mixed type graphs, they should be converted to the same type.
+
+ Attributes from the graph, nodes, and edges are not copied to the new
+ graph.
+
+ The resulting graph can be updated with attributes if desired. For example, code which adds the minimum attribute for each node across all graphs could work.
+ >>> g = nx.Graph()
+ >>> g.add_node(0, capacity=4)
+ >>> g.add_node(1, capacity=3)
+ >>> g.add_edge(0, 1)
+
+ >>> h = g.copy()
+ >>> h.nodes[0]["capacity"] = 2
+
+ >>> gh = nx.intersection_all([g, h])
+
+ >>> new_node_attr = {
+ ... n: min(*(anyG.nodes[n].get("capacity", float("inf")) for anyG in [g, h]))
+ ... for n in gh
+ ... }
+ >>> nx.set_node_attributes(gh, new_node_attr, "new_capacity")
+ >>> gh.nodes(data=True)
+ NodeDataView({0: {'new_capacity': 2}, 1: {'new_capacity': 3}})
+
+ Examples
+ --------
+ >>> G1 = nx.Graph([(1, 2), (2, 3)])
+ >>> G2 = nx.Graph([(2, 3), (3, 4)])
+ >>> R = nx.intersection_all([G1, G2])
+ >>> list(R.nodes())
+ [2, 3]
+ >>> list(R.edges())
+ [(2, 3)]
+
+ """
+ R = None
+
+ for i, G in enumerate(graphs):
+ G_nodes_set = set(G.nodes)
+ G_edges_set = set(G.edges)
+ if not G.is_directed():
+ if G.is_multigraph():
+ G_edges_set.update((v, u, k) for u, v, k in list(G_edges_set))
+ else:
+ G_edges_set.update((v, u) for u, v in list(G_edges_set))
+ if i == 0:
+ # create new graph
+ R = G.__class__()
+ node_intersection = G_nodes_set
+ edge_intersection = G_edges_set
+ elif G.is_directed() != R.is_directed():
+ raise nx.NetworkXError("All graphs must be directed or undirected.")
+ elif G.is_multigraph() != R.is_multigraph():
+ raise nx.NetworkXError("All graphs must be graphs or multigraphs.")
+ else:
+ node_intersection &= G_nodes_set
+ edge_intersection &= G_edges_set
+
+ if R is None:
+ raise ValueError("cannot apply intersection_all to an empty list")
+
+ R.add_nodes_from(node_intersection)
+ R.add_edges_from(edge_intersection)
+
+ return R