Repository: networkx/networkx

Issue:
Return type of `general_k_edge_subgraphs` is incorrect in docstring
In networkx 3.2.1, `general_k_edge_subgraphs` return type in docstring says this:
```
    k_edge_subgraphs : a generator of nx.Graphs that are k-edge-subgraphs
        Each k-edge-subgraph is a maximal set of nodes that defines a subgraph
        of G that is k-edge-connected.
```
However, it actually _yields_ (not returns) _graphs_, not sets of nodes.

Discussion:

Patch:
diff --git a/doc/reference/generators.rst b/doc/reference/generators.rst
index 14fbb5948..d3b980fec 100644
--- a/doc/reference/generators.rst
+++ b/doc/reference/generators.rst
@@ -34,6 +34,7 @@ Classic
    dorogovtsev_goltsev_mendes_graph
    empty_graph
    full_rary_tree
+   kneser_graph
    ladder_graph
    lollipop_graph
    null_graph
diff --git a/networkx/algorithms/connectivity/edge_kcomponents.py b/networkx/algorithms/connectivity/edge_kcomponents.py
index d2ed1ac5c..9dcdf71a2 100644
--- a/networkx/algorithms/connectivity/edge_kcomponents.py
+++ b/networkx/algorithms/connectivity/edge_kcomponents.py
@@ -505,17 +505,24 @@ def _high_degree_components(G, k):
 
 @nx._dispatchable
 def general_k_edge_subgraphs(G, k):
-    """General algorithm to find all maximal k-edge-connected subgraphs in G.
+    """General algorithm to find all maximal k-edge-connected subgraphs in `G`.
 
-    Returns
-    -------
-    k_edge_subgraphs : a generator of nx.Graphs that are k-edge-subgraphs
-        Each k-edge-subgraph is a maximal set of nodes that defines a subgraph
-        of G that is k-edge-connected.
+    Parameters
+    ----------
+    G : nx.Graph
+       Graph in which all maximal k-edge-connected subgraphs will be found.
+
+    k : int
+
+    Yields
+    ------
+    k_edge_subgraphs : Graph instances that are k-edge-subgraphs
+        Each k-edge-subgraph contains a maximal set of nodes that defines a
+        subgraph of `G` that is k-edge-connected.
 
     Notes
     -----
-    Implementation of the basic algorithm from _[1].  The basic idea is to find
+    Implementation of the basic algorithm from [1]_.  The basic idea is to find
     a global minimum cut of the graph. If the cut value is at least k, then the
     graph is a k-edge-connected subgraph and can be added to the results.
     Otherwise, the cut is used to split the graph in two and the procedure is
@@ -524,7 +531,7 @@ def general_k_edge_subgraphs(G, k):
     a single node or a subgraph of G that is k-edge-connected.
 
     This implementation contains optimizations for reducing the number of calls
-    to max-flow, but there are other optimizations in _[1] that could be
+    to max-flow, but there are other optimizations in [1]_ that could be
     implemented.
 
     References
@@ -547,7 +554,7 @@ def general_k_edge_subgraphs(G, k):
     ...     (14, 101, 24),
     ... ]
     >>> G = nx.Graph(it.chain(*[pairwise(path) for path in paths]))
-    >>> sorted(map(len, k_edge_subgraphs(G, k=3)))
+    >>> sorted(len(k_sg) for k_sg in k_edge_subgraphs(G, k=3))
     [1, 1, 1, 4, 4]
     """
     if k < 1:
diff --git a/networkx/generators/classic.py b/networkx/generators/classic.py
index e220f82d8..14ed49ecb 100644
--- a/networkx/generators/classic.py
+++ b/networkx/generators/classic.py
@@ -30,6 +30,7 @@ __all__ = [
     "dorogovtsev_goltsev_mendes_graph",
     "empty_graph",
     "full_rary_tree",
+    "kneser_graph",
     "ladder_graph",
     "lollipop_graph",
     "null_graph",
@@ -103,6 +104,53 @@ def full_rary_tree(r, n, create_using=None):
     return G
 
 
+@nx._dispatchable(graphs=None)
+def kneser_graph(n, k):
+    """Returns the Kneser Graph with parameters `n` and `k`.
+
+    The Kneser Graph has nodes that are k-tuples (subsets) of the integers
+    between 0 and ``n-1``. Nodes are adjacent if their corresponding sets are disjoint.
+
+    Parameters
+    ----------
+    n: int
+        Number of integers from which to make node subsets.
+        Subsets are drawn from ``set(range(n))``.
+    k: int
+        Size of the subsets.
+
+    Returns
+    -------
+    G : NetworkX Graph
+
+    Examples
+    --------
+    >>> G = nx.kneser_graph(5, 2)
+    >>> G.number_of_nodes()
+    10
+    >>> G.number_of_edges()
+    15
+    >>> nx.is_isomorphic(G, nx.petersen_graph())
+    True
+    """
+    if n <= 0:
+        raise NetworkXError("n should be greater than zero")
+    if k <= 0 or k > n:
+        raise NetworkXError("k should be greater than zero and smaller than n")
+
+    G = nx.Graph()
+    # Create all k-subsets of [0, 1, ..., n-1]
+    subsets = list(itertools.combinations(range(n), k))
+
+    if 2 * k > n:
+        G.add_nodes_from(subsets)
+
+    universe = set(range(n))
+    comb = itertools.combinations  # only to make it all fit on one line
+    G.add_edges_from((s, t) for s in subsets for t in comb(universe - set(s), k))
+    return G
+
+
 @nx._dispatchable(graphs=None)
 def balanced_tree(r, h, create_using=None):
     """Returns the perfectly balanced `r`-ary tree of height `h`.


Test patch:
diff --git a/networkx/generators/tests/test_classic.py b/networkx/generators/tests/test_classic.py
index 5e24c7779..cf03d3ea7 100644
--- a/networkx/generators/tests/test_classic.py
+++ b/networkx/generators/tests/test_classic.py
@@ -617,3 +617,19 @@ class TestGeneratorClassic:
                 assert G.nodes[u] != G.nodes[v]
         with pytest.raises(nx.NetworkXError, match="Negative number of nodes"):
             nx.complete_multipartite_graph(2, -3, 4)
+
+    def test_kneser_graph(self):
+        # the petersen graph is a special case of the kneser graph when n=5 and k=2
+        assert is_isomorphic(nx.kneser_graph(5, 2), nx.petersen_graph())
+
+        # when k is 1, the kneser graph returns a complete graph with n vertices
+        for i in range(1, 7):
+            assert is_isomorphic(nx.kneser_graph(i, 1), nx.complete_graph(i))
+
+        # the kneser graph of n and n-1 is the empty graph with n vertices
+        for j in range(3, 7):
+            assert is_isomorphic(nx.kneser_graph(j, j - 1), nx.empty_graph(j))
+
+        # in general the number of edges of the kneser graph is equal to
+        # (n choose k) times (n-k choose k) divided by 2
+        assert nx.number_of_edges(nx.kneser_graph(8, 3)) == 280