|
""" |
|
Algorithm to find a maximal (not maximum) independent set. |
|
|
|
""" |
|
import networkx as nx |
|
from networkx.utils import not_implemented_for, py_random_state |
|
|
|
__all__ = ["maximal_independent_set"] |
|
|
|
|
|
@not_implemented_for("directed") |
|
@py_random_state(2) |
|
@nx._dispatchable |
|
def maximal_independent_set(G, nodes=None, seed=None): |
|
"""Returns a random maximal independent set guaranteed to contain |
|
a given set of nodes. |
|
|
|
An independent set is a set of nodes such that the subgraph |
|
of G induced by these nodes contains no edges. A maximal |
|
independent set is an independent set such that it is not possible |
|
to add a new node and still get an independent set. |
|
|
|
Parameters |
|
---------- |
|
G : NetworkX graph |
|
|
|
nodes : list or iterable |
|
Nodes that must be part of the independent set. This set of nodes |
|
must be independent. |
|
|
|
seed : integer, random_state, or None (default) |
|
Indicator of random number generation state. |
|
See :ref:`Randomness<randomness>`. |
|
|
|
Returns |
|
------- |
|
indep_nodes : list |
|
List of nodes that are part of a maximal independent set. |
|
|
|
Raises |
|
------ |
|
NetworkXUnfeasible |
|
If the nodes in the provided list are not part of the graph or |
|
do not form an independent set, an exception is raised. |
|
|
|
NetworkXNotImplemented |
|
If `G` is directed. |
|
|
|
Examples |
|
-------- |
|
>>> G = nx.path_graph(5) |
|
>>> nx.maximal_independent_set(G) # doctest: +SKIP |
|
[4, 0, 2] |
|
>>> nx.maximal_independent_set(G, [1]) # doctest: +SKIP |
|
[1, 3] |
|
|
|
Notes |
|
----- |
|
This algorithm does not solve the maximum independent set problem. |
|
|
|
""" |
|
if not nodes: |
|
nodes = {seed.choice(list(G))} |
|
else: |
|
nodes = set(nodes) |
|
if not nodes.issubset(G): |
|
raise nx.NetworkXUnfeasible(f"{nodes} is not a subset of the nodes of G") |
|
neighbors = set.union(*[set(G.adj[v]) for v in nodes]) |
|
if set.intersection(neighbors, nodes): |
|
raise nx.NetworkXUnfeasible(f"{nodes} is not an independent set of G") |
|
indep_nodes = list(nodes) |
|
available_nodes = set(G.nodes()).difference(neighbors.union(nodes)) |
|
while available_nodes: |
|
node = seed.choice(list(available_nodes)) |
|
indep_nodes.append(node) |
|
available_nodes.difference_update(list(G.adj[node]) + [node]) |
|
return indep_nodes |
|
|