Repository: networkx/networkx

Issue:
Approximation TSP - Bug when custom weight is not correctly add in input
<!-- 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 -->
When the weight has a different label than 'weight', it is not properly considered `networkx.algorithms.approximation.traveling_salesman.threshold_accepting_tsp` ( it ius working for the `greedy`approximation but I didnt check the others approximations)


### Current Behavior
```python
import networkx as nx
from networkx.algorithms import approximation as approx
from networkx.utils import pairwise

G = nx.DiGraph()
G.add_weighted_edges_from({
    ("A", "B", 3), ("A", "C", 17), ("A", "D", 14), ("B", "A", 3),
    ("B", "C", 12), ("B", "D", 16), ("C", "A", 13),("C", "B", 12),
    ("C", "D", 4), ("D", "A", 14), ("D", "B", 15), ("D", "C", 2)
})
cycle = approx.greedy_tsp(G, source="D")
cost = sum(G[n][nbr]["weight"] for n, nbr in pairwise(cycle))
print(cycle)
print(cost)


# Test new graph with weight attribute 'length'
H = nx.DiGraph()
H.add_edges_from([
    ("A", "B", {'length':3}), ("A", "C", {'length':17}), ("A", "D", {'length':14}), ("B", "A", {'length':3}),
    ("B", "C", {'length':12}), ("B", "D", {'length':16}), ("C", "A", {'length':13}),("C", "B", {'length':12}),
    ("C", "D", {'length':4}), ("D", "A", {'length':14}), ("D", "B", {'length':15}), ("D", "C", {'length':2})
])
cycle = approx.greedy_tsp(H, weight='length',source="D")
cost = sum(H[n][nbr]["length"] for n, nbr in pairwise(cycle))
print(cycle)
print(cost)

print(nx.approximation.threshold_accepting_tsp(H, "greedy", weight='length', source='D'))

tsp = nx.approximation.traveling_salesman_problem
TA_tsp = nx.approximation.threshold_accepting_tsp
method = lambda Graph, wt: TA_tsp(Graph, "greedy", weight=wt, source='D')
path = tsp(H, weight='length', cycle=True, method=method)
print(path)

path = tsp(G, cycle=True, method=method)
print(path)
```

```
['D', 'C', 'B', 'A', 'D']
31
['D', 'C', 'B', 'A', 'D']
31
['D', 'C', 'B', 'A', 'D']
['D', 'C', 'B', 'C', 'A', 'D']
['D', 'C', 'B', 'A', 'D']
```

### Expected behavior:

```python
tsp = nx.approximation.traveling_salesman_problem
TA_tsp = nx.approximation.threshold_accepting_tsp
method = lambda Graph, wt: TA_tsp(Graph, "greedy", weight=wt, source='D')
path = tsp(H, weight='length', cycle=True, method=method)
```
returns `['D', 'C', 'B', 'C', 'A', 'D']` but it should return `['D', 'C', 'B', 'A', 'D']`

### Environment
<!--- Please provide details about your local environment -->
Python version: 3.9.4
NetworkX version: 2.6rc1.dev0


### Additional context
<!--- Add any other context about the problem here, screenshots, etc. -->
The problem may come from the way `nx.approximation.traveling_salesman_problem` is handling custom weight?  

Have you considered not assigning a default weight of 1 when the weight attribute is not present? I think it could make the software more "robust" maybe?

For example, when running the command below:
```python
cycle = approx.greedy_tsp(H, source="D")
cost = sum(H[n][nbr]["length"] for n, nbr in nx.utils.pairwise(cycle))
print(cycle)
print(cost)
```
I got:
```
['D', 'B', 'C', 'A', 'D']
54
```

But it is not the behavior I would expect. I would rather have the approximation made on the only edge attribute available ("length") or getting an error message telling me `"Weight attribute not present "` .





Discussion:
Thanks very much for this!!

It looks like the calling order of `threshold_accepting_tsp` is not being respected in the code or in the docs. This should be fixed and tests added.  Code is near line 285 and docs in that function as well as the init_cycle argument to `threshold_accepting_tsp`.

Resolving patch:
diff --git a/networkx/algorithms/approximation/traveling_salesman.py b/networkx/algorithms/approximation/traveling_salesman.py
--- a/networkx/algorithms/approximation/traveling_salesman.py
+++ b/networkx/algorithms/approximation/traveling_salesman.py
@@ -447,13 +447,11 @@ def simulated_annealing_tsp(
         The distance between all pairs of nodes should be included.
 
     init_cycle : list of all nodes or "greedy"
-        The initial solution (a cycle through all nodes).
-        Usually you should use `greedy_tsp(G, weight)`.
-        But you can start with `list(G)` or the final result
-        of `simulated_annealing_tsp` when doing `threshold_accepting_tsp`.
-
-        This argument is required. A shortcut if you don't want to think
-        about it is to use the string "greedy" which calls `greedy_tsp`.
+        The initial solution (a cycle through all nodes returning to the start).
+        This argument has no default to make you think about it.
+        If "greedy", use `greedy_tsp(G, weight)`.
+        Other common starting cycles are `list(G) + [next(iter(G))]` or the final
+        result of `simulated_annealing_tsp` when doing `threshold_accepting_tsp`.
 
     weight : string, optional (default="weight")
         Edge data key corresponding to the edge weight.
@@ -663,6 +661,13 @@ def threshold_accepting_tsp(
         `G` should be a complete weighted undirected graph.
         The distance between all pairs of nodes should be included.
 
+    init_cycle : list or "greedy"
+        The initial solution (a cycle through all nodes returning to the start).
+        This argument has no default to make you think about it.
+        If "greedy", use `greedy_tsp(G, weight)`.
+        Other common starting cycles are `list(G) + [next(iter(G))]` or the final
+        result of `simulated_annealing_tsp` when doing `threshold_accepting_tsp`.
+
     weight : string, optional (default="weight")
         Edge data key corresponding to the edge weight.
         If any edge does not have this attribute the weight is set to 1.
@@ -713,9 +718,6 @@ def threshold_accepting_tsp(
         least one acceptance of a neighbor solution.
         If no inner loop moves are accepted the threshold remains unchanged.
 
-    cycle : list, optional (default=compute using greedy algorithm)
-        The initial solution (a cycle all nodes).
-
     seed : integer, random_state, or None (default)
         Indicator of random number generation state.
         See :ref:`Randomness<randomness>`.


Test patch:
diff --git a/networkx/algorithms/approximation/tests/test_traveling_salesman.py b/networkx/algorithms/approximation/tests/test_traveling_salesman.py
--- a/networkx/algorithms/approximation/tests/test_traveling_salesman.py
+++ b/networkx/algorithms/approximation/tests/test_traveling_salesman.py
@@ -210,6 +210,11 @@ def test_simulated_annealing_undirected(self):
         cost = sum(self.UG2[n][nbr]["weight"] for n, nbr in pairwise(cycle))
         validate_symmetric_solution(cycle, cost, self.UG2_cycle, self.UG2_cost)
 
+    def test_error_on_input_order_mistake(self):
+        # see issue #4846 https://github.com/networkx/networkx/issues/4846
+        pytest.raises(TypeError, self.tsp, self.UG, weight="weight")
+        pytest.raises(nx.NetworkXError, self.tsp, self.UG, "weight")
+
     def test_not_complete_graph(self):
         pytest.raises(
             nx.NetworkXError,