Repository: networkx/networkx

Issue:
I have a question about `nx.optimal_edit_paths(G1, G2)`.


I have been conducting a experiment for computing graph similarity.  
I have a question about `nx.optimal_edit_paths(G1, G2)`.
In the [documentation of it](https://networkx.github.io/documentation/stable/reference/algorithms/generated/networkx.algorithms.similarity.optimal_edit_paths.html), it is written that this function **Returns all minimum-cost edit paths transforming G1 to G2**. 

I use the function in my code and I run it. my code is below. 
Even though `G1` and `G2` are exactly same graph and their graph_edit_cost is 0, 
there a a lot of optimal_edit_paths. 

```python
N = 3
G1 = nx.complete_graph(N)
G2 = nx.complete_graph(N)

edit_path, graph_edit_cost = nx.optimal_edit_paths(G1, G2)
print(f"graph edit cost: {graph_edit_cost}")
for p in edit_path:
    node_edit, edge_edit = p
    print(f"node_edit: {node_edit}")
    print(f"edge_edit: {edge_edit}")
    print("--"*30)
```

the output is below. 
As I said it before, graph_edit_cost is zero because `G1` and `G2` are exactly same graphs. 
but there are lots of optimal path when paths was derived by `nx.optimal_edit_paths(G1, G2)`. 
I don't know why this happend. It doesn't look like 'optimal' because they don't have same edit cost. 

```
graph edit cost: 0.0
node_edit: [(0, 0), (1, 1), (2, 2)]
edge_edit: [((0, 1), (0, 1)), ((0, 2), (0, 2)), ((1, 2), (1, 2))]
------------------------------------------------------------
node_edit: [(0, 0), (2, 1), (1, 2)]
edge_edit: [((0, 2), (0, 1)), ((0, 1), (0, 2)), ((1, 2), (1, 2))]
------------------------------------------------------------
node_edit: [(1, 0), (0, 1), (2, 2)]
edge_edit: [((0, 1), (0, 1)), ((0, 2), (1, 2)), ((1, 2), (0, 2))]
------------------------------------------------------------
node_edit: [(1, 0), (2, 1), (0, 2)]
edge_edit: [((1, 2), (0, 1)), ((0, 1), (0, 2)), ((0, 2), (1, 2))]
------------------------------------------------------------
node_edit: [(2, 0), (0, 1), (1, 2)]
edge_edit: [((0, 2), (0, 1)), ((0, 1), (1, 2)), ((1, 2), (0, 2))]
------------------------------------------------------------
node_edit: [(2, 0), (1, 1), (0, 2)]
edge_edit: [((1, 2), (0, 1)), ((0, 1), (1, 2)), ((0, 2), (0, 2))]
------------------------------------------------------------
```

And also, if the function is correct, How can I transform `G1` to `G2` base on that operations(node_edit, edge_edit)? I don't know how those operations have to be applied to `G2` to make `G2`. 


I always appreciate your help in this library. 
becasue of that, I've learned a lot about network science. 

If you feel my text is rude or not polite, it is because of my lack of english. 
sorry about that. 


Discussion:
> If you feel my text is rude or not polite, it is because of my lack of english. sorry about that.

Nothing at all to be sorry about @frhyme , thanks for the question.

I'm not familiar at all with `optimal_edit_paths`, but I just wanted to call your attention to #4102 - maybe the discussion will prove useful.
This question is quite old, and I think a complete answer requires looking at the reference paper to see how they count the number of edits and in particular how they check for isomorphism with ```G2``` after the edits. But here's a partial answer:

The edit paths you report all have 3 node edits and 3 edge edits. That means the length of those two lists is 6 total for all of the edit paths. They are equivalent despite the first being the "identity path"(? a term I just made up).

But, as you point out, the two graphs are isomorphic, so the edit distance should be 0 if distance is the number of changes needed to make G1 isomorphic to G2.

I suspect the algorithm actually computes the number of changes needed to convert ```G1``` to ```G2```. Said another way, it doesn't count the 6 edits as part of the edit cost.  In fact if you look closely, these 6 paths consist precisely of the isomorphism mappings from ```G1``` to ```G2```. They are simply renaming the nodes and edges and thus have no cost.

This question shows that the documentation needs more information about what is returned here (i.e. what is an edit path?).  That should be sufficient to close this Question.
It sounds like the documentation should be improved along the lines discussed above in order to close this one.

Resolving patch:
diff --git a/networkx/algorithms/similarity.py b/networkx/algorithms/similarity.py
--- a/networkx/algorithms/similarity.py
+++ b/networkx/algorithms/similarity.py
@@ -322,7 +322,8 @@ def optimal_edit_paths(
         edge_edit_path : list of tuples ((u1, v1), (u2, v2))
 
     cost : numeric
-        Optimal edit path cost (graph edit distance).
+        Optimal edit path cost (graph edit distance). When the cost
+        is zero, it indicates that `G1` and `G2` are isomorphic.
 
     Examples
     --------
@@ -334,6 +335,14 @@ def optimal_edit_paths(
     >>> cost
     5.0
 
+    Notes
+    -----
+    To transform `G1` into a graph isomorphic to `G2`, apply the node
+    and edge edits in the returned ``edit_paths``.
+    In the case of isomorphic graphs, the cost is zero, and the paths
+    represent different isomorphic mappings (isomorphisms). That is, the
+    edits involve renaming nodes and edges to match the structure of `G2`.
+
     See Also
     --------
     graph_edit_distance, optimize_edit_paths


Test patch: