Repository: networkx/networkx

Issue:
Condition in `test_louvain::test_threshold` not representative of graphs with same parameters but different seed.
<!-- If you have a general question about NetworkX, please use the discussions tab to create a new discussion -->

<!--- Provide a general summary of the issue in the Title above -->

### Current Behavior

```
def test_threshold():
    G = nx.LFR_benchmark_graph(
        250, 3, 1.5, 0.009, average_degree=5, min_community=20, seed=10
    )
    partition1 = nx.community.louvain_communities(G, threshold=0.3, seed=2)
    partition2 = nx.community.louvain_communities(G, seed=2)
    mod1 = nx.community.modularity(G, partition1)
    mod2 = nx.community.modularity(G, partition2)

    assert mod1 < mod2
```
The test for the Louvain algorithm asserts if the modularity of a partition obtained using `threshold=0.3` is smaller than the modularity  when using the default value for a specific graph generated using the `LFR_benchmark_graph`. However, if the graph used for testing is changed, this condition no longer holds in general (see Steps to Reproduce). 

### Expected Behavior

I suggest changing the test to `assert mod1 <= mod2` instead. 

### Steps to Reproduce

If we use the same settings for the graph generation but allow for a different seed we do not always pass the assertion.

```
generating = True
tries = 0
while generating:
    seed = np.random.randint(50000) 
    try:
        G = nx.LFR_benchmark_graph(250, 3, 1.5, 0.009, average_degree = 5, min_community = 20, seed = seed)
        print(f'generated graph {seed}')
        generating = False
    except:
        tries += 1
print(tries)

check = 0
for i in range(100):
    random_seed = np.random.randint(50000)
    p1 = nx.community.louvain_communities(G, threshold = 0.3, seed = random_seed)
    p2 = nx.community.louvain_communities(G, seed = random_seed)
    m1 = nx.community.modularity(G, p1)
    m2 = nx.community.modularity(G, p2)
    print(m1, m2)
    if m1 < m2:
        check += 1
print(check)
```

On my machine, it took 28 tries to generate a graph (seed = 26537). For this graph, the test was successful 83/100 times. If we relax the test condition to `assert m1 <= m2` the test succeeds 100/100 times.

### Environment

<!--- Please provide details about your local environment -->

Python version: 3.10
NetworkX version: 3.1



Discussion:

Patch:
diff --git a/networkx/algorithms/approximation/clustering_coefficient.py b/networkx/algorithms/approximation/clustering_coefficient.py
index f95c86d2a..545fc6553 100644
--- a/networkx/algorithms/approximation/clustering_coefficient.py
+++ b/networkx/algorithms/approximation/clustering_coefficient.py
@@ -45,6 +45,11 @@ def average_clustering(G, trials=1000, seed=None):
     >>> approximation.average_clustering(G, trials=1000, seed=10)
     0.214
 
+    Raises
+    ------
+    NetworkXNotImplemented
+        If G is directed.
+
     References
     ----------
     .. [1] Schank, Thomas, and Dorothea Wagner. Approximating clustering
diff --git a/networkx/algorithms/approximation/distance_measures.py b/networkx/algorithms/approximation/distance_measures.py
index a6fece661..d5847e65a 100644
--- a/networkx/algorithms/approximation/distance_measures.py
+++ b/networkx/algorithms/approximation/distance_measures.py
@@ -40,6 +40,15 @@ def diameter(G, seed=None):
     d : integer
        Lower Bound on the Diameter of G
 
+    Examples
+    --------
+    >>> G = nx.path_graph(10)  # undirected graph
+    >>> nx.diameter(G)
+    9
+    >>> G = nx.cycle_graph(3, create_using=nx.DiGraph)  # directed graph
+    >>> nx.diameter(G)
+    2
+
     Raises
     ------
     NetworkXError
diff --git a/networkx/algorithms/approximation/dominating_set.py b/networkx/algorithms/approximation/dominating_set.py
index 691564cf9..06ab97d97 100644
--- a/networkx/algorithms/approximation/dominating_set.py
+++ b/networkx/algorithms/approximation/dominating_set.py
@@ -43,6 +43,17 @@ def min_weighted_dominating_set(G, weight=None):
         each node in the graph and `w(V^*)` denotes the sum of the
         weights of each node in the minimum weight dominating set.
 
+    Examples
+    --------
+    >>> G = nx.Graph([(0, 1), (0, 4), (1, 4), (1, 2), (2, 3), (3, 4), (2, 5)])
+    >>> nx.approximation.min_weighted_dominating_set(G)
+    {1, 2, 4}
+
+    Raises
+    ------
+    NetworkXNotImplemented
+        If G is directed.
+
     Notes
     -----
     This algorithm computes an approximate minimum weighted dominating
@@ -115,6 +126,17 @@ def min_edge_dominating_set(G):
     min_edge_dominating_set : set
       Returns a set of dominating edges whose size is no more than 2 * OPT.
 
+    Examples
+    --------
+    >>> G = nx.petersen_graph()
+    >>> nx.approximation.min_edge_dominating_set(G)
+    {(0, 1), (4, 9), (6, 8), (5, 7), (2, 3)}
+
+    Raises
+    ------
+    ValueError
+        If the input graph `G` is empty.
+
     Notes
     -----
     The algorithm computes an approximate solution to the edge dominating set
diff --git a/networkx/algorithms/approximation/maxcut.py b/networkx/algorithms/approximation/maxcut.py
index 0c30d224d..f4e1da87c 100644
--- a/networkx/algorithms/approximation/maxcut.py
+++ b/networkx/algorithms/approximation/maxcut.py
@@ -39,6 +39,20 @@ def randomized_partitioning(G, seed=None, p=0.5, weight=None):
 
     partition : pair of node sets
         A partitioning of the nodes that defines a minimum cut.
+
+    Examples
+    --------
+    >>> G = nx.complete_graph(5)
+    >>> cut_size, partition = nx.approximation.randomized_partitioning(G, seed=1)
+    >>> cut_size
+    6
+    >>> partition
+    ({0, 3, 4}, {1, 2})
+
+    Raises
+    ------
+    NetworkXNotImplemented
+        If the graph is directed or is a multigraph.
     """
     cut = {node for node in G.nodes() if seed.random() < p}
     cut_size = nx.algorithms.cut_size(G, cut, weight=weight)
@@ -86,6 +100,20 @@ def one_exchange(G, initial_cut=None, seed=None, weight=None):
 
     partition : pair of node sets
         A partitioning of the nodes that defines a maximum cut.
+
+    Examples
+    --------
+    >>> G = nx.complete_graph(5)
+    >>> curr_cut_size, partition = nx.approximation.one_exchange(G, seed=1)
+    >>> curr_cut_size
+    6
+    >>> partition
+    ({0, 2}, {1, 3, 4})
+
+    Raises
+    ------
+    NetworkXNotImplemented
+        If the graph is directed or is a multigraph.
     """
     if initial_cut is None:
         initial_cut = set()
diff --git a/networkx/algorithms/approximation/steinertree.py b/networkx/algorithms/approximation/steinertree.py
index af5916442..9b5c99488 100644
--- a/networkx/algorithms/approximation/steinertree.py
+++ b/networkx/algorithms/approximation/steinertree.py
@@ -64,7 +64,7 @@ def _mehlhorn_steiner_tree(G, terminal_nodes, weight):
         if not G_1_prime.has_edge(su, sv):
             G_1_prime.add_edge(su, sv, weight=weight_here)
         else:
-            new_weight = min(weight_here, G_1_prime[su][sv][weight])
+            new_weight = min(weight_here, G_1_prime[su][sv]["weight"])
             G_1_prime.add_edge(su, sv, weight=new_weight)
 
     G_2 = nx.minimum_spanning_edges(G_1_prime, data=True)
@@ -195,20 +195,12 @@ def steiner_tree(G, terminal_nodes, weight="weight", method=None):
            https://doi.org/10.1016/0020-0190(88)90066-X.
     """
     if method is None:
-        import warnings
-
-        msg = (
-            "steiner_tree will change default method from 'kou' to 'mehlhorn' "
-            "in version 3.2.\nSet the `method` kwarg to remove this warning."
-        )
-        warnings.warn(msg, FutureWarning, stacklevel=4)
-        method = "kou"
+        method = "mehlhorn"
 
     try:
         algo = ALGORITHMS[method]
     except KeyError as e:
-        msg = f"{method} is not a valid choice for an algorithm."
-        raise ValueError(msg) from e
+        raise ValueError(f"{method} is not a valid choice for an algorithm.") from e
 
     edges = algo(G, terminal_nodes, weight)
     # For multigraph we should add the minimal weight edge keys
diff --git a/networkx/generators/small.py b/networkx/generators/small.py
index ea33e7419..acd2fbc7a 100644
--- a/networkx/generators/small.py
+++ b/networkx/generators/small.py
@@ -64,36 +64,51 @@ def LCF_graph(n, shift_list, repeats, create_using=None):
     """
     Return the cubic graph specified in LCF notation.
 
-    LCF notation (LCF=Lederberg-Coxeter-Fruchte) is a compressed
+    LCF (Lederberg-Coxeter-Fruchte) notation[1]_ is a compressed
     notation used in the generation of various cubic Hamiltonian
-    graphs of high symmetry. See, for example, dodecahedral_graph,
-    desargues_graph, heawood_graph and pappus_graph below.
+    graphs of high symmetry. See, for example, `dodecahedral_graph`,
+    `desargues_graph`, `heawood_graph` and `pappus_graph`.
 
-    n (number of nodes)
-      The starting graph is the n-cycle with nodes 0,...,n-1.
-      (The null graph is returned if n < 0.)
+    Nodes are drawn from ``range(n)``. Each node ``n_i`` is connected with
+    node ``n_i + shift % n`` where ``shift`` is given by cycling through
+    the input `shift_list` `repeat` s times.
 
-    shift_list = [s1,s2,..,sk], a list of integer shifts mod n,
+    Parameters
+    ----------
+    n : int
+       The starting graph is the `n`-cycle with nodes ``0, ..., n-1``.
+       The null graph is returned if `n` < 1.
 
-    repeats
-      integer specifying the number of times that shifts in shift_list
-      are successively applied to each v_current in the n-cycle
-      to generate an edge between v_current and v_current+shift mod n.
+    shift_list : list
+       A list of integer shifts mod `n`, ``[s1, s2, .., sk]``
 
-    For v1 cycling through the n-cycle a total of k*repeats
-    with shift cycling through shiftlist repeats times connect
-    v1 with v1+shift mod n
+    repeats : int
+       Integer specifying the number of times that shifts in `shift_list`
+       are successively applied to each current node in the n-cycle
+       to generate an edge between ``n_current`` and ``n_current + shift mod n``.
 
+    Returns
+    -------
+    G : Graph
+       A graph instance created from the specified LCF notation.
+
+    Examples
+    --------
     The utility graph $K_{3,3}$
 
     >>> G = nx.LCF_graph(6, [3, -3], 3)
+    >>> G.edges()
+    EdgeView([(0, 1), (0, 5), (0, 3), (1, 2), (1, 4), (2, 3), (2, 5), (3, 4), (4, 5)])
 
-    The Heawood graph
+    The Heawood graph:
 
     >>> G = nx.LCF_graph(14, [5, -5], 7)
+    >>> nx.is_isomorphic(G, nx.heawood_graph())
+    True
 
-    See http://mathworld.wolfram.com/LCFNotation.html for a description
-    and references.
+    References
+    ----------
+    .. [1] https://en.wikipedia.org/wiki/LCF_notation
 
     """
     if n <= 0:


Test patch:
diff --git a/networkx/algorithms/approximation/tests/test_steinertree.py b/networkx/algorithms/approximation/tests/test_steinertree.py
index d7af1a1af..95733f16e 100644
--- a/networkx/algorithms/approximation/tests/test_steinertree.py
+++ b/networkx/algorithms/approximation/tests/test_steinertree.py
@@ -189,3 +189,22 @@ class TestSteinerTree:
         for method in self.methods:
             S = steiner_tree(G, terminal_nodes, method=method)
             assert edges_equal(S.edges(data=True, keys=True), expected_edges)
+
+
+@pytest.mark.parametrize("method", ("kou", "mehlhorn"))
+def test_steiner_tree_weight_attribute(method):
+    G = nx.star_graph(4)
+    # Add an edge attribute that is named something other than "weight"
+    nx.set_edge_attributes(G, {e: 10 for e in G.edges}, name="distance")
+    H = nx.approximation.steiner_tree(G, [1, 3], method=method, weight="distance")
+    assert nx.utils.edges_equal(H.edges, [(0, 1), (0, 3)])
+
+
+@pytest.mark.parametrize("method", ("kou", "mehlhorn"))
+def test_steiner_tree_multigraph_weight_attribute(method):
+    G = nx.cycle_graph(3, create_using=nx.MultiGraph)
+    nx.set_edge_attributes(G, {e: 10 for e in G.edges}, name="distance")
+    G.add_edge(2, 0, distance=5)
+    H = nx.approximation.steiner_tree(G, list(G), method=method, weight="distance")
+    assert len(H.edges) == 2 and H.has_edge(2, 0, key=1)
+    assert sum(dist for *_, dist in H.edges(data="distance")) == 15
diff --git a/networkx/algorithms/community/tests/test_louvain.py b/networkx/algorithms/community/tests/test_louvain.py
index b47fb74c5..816e6f143 100644
--- a/networkx/algorithms/community/tests/test_louvain.py
+++ b/networkx/algorithms/community/tests/test_louvain.py
@@ -236,7 +236,7 @@ def test_threshold():
     mod1 = nx.community.modularity(G, partition1)
     mod2 = nx.community.modularity(G, partition2)
 
-    assert mod1 < mod2
+    assert mod1 <= mod2
 
 
 def test_empty_graph():