aboutsummaryrefslogtreecommitdiff
path: root/.venv/lib/python3.12/site-packages/networkx/algorithms/regular.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/regular.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/regular.py')
-rw-r--r--.venv/lib/python3.12/site-packages/networkx/algorithms/regular.py215
1 files changed, 215 insertions, 0 deletions
diff --git a/.venv/lib/python3.12/site-packages/networkx/algorithms/regular.py b/.venv/lib/python3.12/site-packages/networkx/algorithms/regular.py
new file mode 100644
index 00000000..f483ef32
--- /dev/null
+++ b/.venv/lib/python3.12/site-packages/networkx/algorithms/regular.py
@@ -0,0 +1,215 @@
+"""Functions for computing and verifying regular graphs."""
+
+import networkx as nx
+from networkx.utils import not_implemented_for
+
+__all__ = ["is_regular", "is_k_regular", "k_factor"]
+
+
+@nx._dispatchable
+def is_regular(G):
+ """Determines whether the graph ``G`` is a regular graph.
+
+ A regular graph is a graph where each vertex has the same degree. A
+ regular digraph is a graph where the indegree and outdegree of each
+ vertex are equal.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ Returns
+ -------
+ bool
+ Whether the given graph or digraph is regular.
+
+ Examples
+ --------
+ >>> G = nx.DiGraph([(1, 2), (2, 3), (3, 4), (4, 1)])
+ >>> nx.is_regular(G)
+ True
+
+ """
+ if len(G) == 0:
+ raise nx.NetworkXPointlessConcept("Graph has no nodes.")
+ n1 = nx.utils.arbitrary_element(G)
+ if not G.is_directed():
+ d1 = G.degree(n1)
+ return all(d1 == d for _, d in G.degree)
+ else:
+ d_in = G.in_degree(n1)
+ in_regular = all(d_in == d for _, d in G.in_degree)
+ d_out = G.out_degree(n1)
+ out_regular = all(d_out == d for _, d in G.out_degree)
+ return in_regular and out_regular
+
+
+@not_implemented_for("directed")
+@nx._dispatchable
+def is_k_regular(G, k):
+ """Determines whether the graph ``G`` is a k-regular graph.
+
+ A k-regular graph is a graph where each vertex has degree k.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+
+ Returns
+ -------
+ bool
+ Whether the given graph is k-regular.
+
+ Examples
+ --------
+ >>> G = nx.Graph([(1, 2), (2, 3), (3, 4), (4, 1)])
+ >>> nx.is_k_regular(G, k=3)
+ False
+
+ """
+ return all(d == k for n, d in G.degree)
+
+
+@not_implemented_for("directed")
+@not_implemented_for("multigraph")
+@nx._dispatchable(preserve_edge_attrs=True, returns_graph=True)
+def k_factor(G, k, matching_weight="weight"):
+ """Compute a k-factor of G
+
+ A k-factor of a graph is a spanning k-regular subgraph.
+ A spanning k-regular subgraph of G is a subgraph that contains
+ each vertex of G and a subset of the edges of G such that each
+ vertex has degree k.
+
+ Parameters
+ ----------
+ G : NetworkX graph
+ Undirected graph
+
+ matching_weight: string, optional (default='weight')
+ Edge data key corresponding to the edge weight.
+ Used for finding the max-weighted perfect matching.
+ If key not found, uses 1 as weight.
+
+ Returns
+ -------
+ G2 : NetworkX graph
+ A k-factor of G
+
+ Examples
+ --------
+ >>> G = nx.Graph([(1, 2), (2, 3), (3, 4), (4, 1)])
+ >>> G2 = nx.k_factor(G, k=1)
+ >>> G2.edges()
+ EdgeView([(1, 2), (3, 4)])
+
+ References
+ ----------
+ .. [1] "An algorithm for computing simple k-factors.",
+ Meijer, Henk, Yurai Núñez-Rodríguez, and David Rappaport,
+ Information processing letters, 2009.
+ """
+
+ from networkx.algorithms.matching import is_perfect_matching, max_weight_matching
+
+ class LargeKGadget:
+ def __init__(self, k, degree, node, g):
+ self.original = node
+ self.g = g
+ self.k = k
+ self.degree = degree
+
+ self.outer_vertices = [(node, x) for x in range(degree)]
+ self.core_vertices = [(node, x + degree) for x in range(degree - k)]
+
+ def replace_node(self):
+ adj_view = self.g[self.original]
+ neighbors = list(adj_view.keys())
+ edge_attrs = list(adj_view.values())
+ for outer, neighbor, edge_attrs in zip(
+ self.outer_vertices, neighbors, edge_attrs
+ ):
+ self.g.add_edge(outer, neighbor, **edge_attrs)
+ for core in self.core_vertices:
+ for outer in self.outer_vertices:
+ self.g.add_edge(core, outer)
+ self.g.remove_node(self.original)
+
+ def restore_node(self):
+ self.g.add_node(self.original)
+ for outer in self.outer_vertices:
+ adj_view = self.g[outer]
+ for neighbor, edge_attrs in list(adj_view.items()):
+ if neighbor not in self.core_vertices:
+ self.g.add_edge(self.original, neighbor, **edge_attrs)
+ break
+ g.remove_nodes_from(self.outer_vertices)
+ g.remove_nodes_from(self.core_vertices)
+
+ class SmallKGadget:
+ def __init__(self, k, degree, node, g):
+ self.original = node
+ self.k = k
+ self.degree = degree
+ self.g = g
+
+ self.outer_vertices = [(node, x) for x in range(degree)]
+ self.inner_vertices = [(node, x + degree) for x in range(degree)]
+ self.core_vertices = [(node, x + 2 * degree) for x in range(k)]
+
+ def replace_node(self):
+ adj_view = self.g[self.original]
+ for outer, inner, (neighbor, edge_attrs) in zip(
+ self.outer_vertices, self.inner_vertices, list(adj_view.items())
+ ):
+ self.g.add_edge(outer, inner)
+ self.g.add_edge(outer, neighbor, **edge_attrs)
+ for core in self.core_vertices:
+ for inner in self.inner_vertices:
+ self.g.add_edge(core, inner)
+ self.g.remove_node(self.original)
+
+ def restore_node(self):
+ self.g.add_node(self.original)
+ for outer in self.outer_vertices:
+ adj_view = self.g[outer]
+ for neighbor, edge_attrs in adj_view.items():
+ if neighbor not in self.core_vertices:
+ self.g.add_edge(self.original, neighbor, **edge_attrs)
+ break
+ self.g.remove_nodes_from(self.outer_vertices)
+ self.g.remove_nodes_from(self.inner_vertices)
+ self.g.remove_nodes_from(self.core_vertices)
+
+ # Step 1
+ if any(d < k for _, d in G.degree):
+ raise nx.NetworkXUnfeasible("Graph contains a vertex with degree less than k")
+ g = G.copy()
+
+ # Step 2
+ gadgets = []
+ for node, degree in list(g.degree):
+ if k < degree / 2.0:
+ gadget = SmallKGadget(k, degree, node, g)
+ else:
+ gadget = LargeKGadget(k, degree, node, g)
+ gadget.replace_node()
+ gadgets.append(gadget)
+
+ # Step 3
+ matching = max_weight_matching(g, maxcardinality=True, weight=matching_weight)
+
+ # Step 4
+ if not is_perfect_matching(g, matching):
+ raise nx.NetworkXUnfeasible(
+ "Cannot find k-factor because no perfect matching exists"
+ )
+
+ for edge in g.edges():
+ if edge not in matching and (edge[1], edge[0]) not in matching:
+ g.remove_edge(edge[0], edge[1])
+
+ for gadget in gadgets:
+ gadget.restore_node()
+
+ return g