Repository: quantumlib/Cirq

Issue:
[Named Topologies] Add `nodes_to_linequbits` method to `LineTopology` 
Routing utilities currently present in cirq contrib expect a networkx graph of device (/target topology) where each node is a `cirq.Qid`.  `NamedTopology` stores topology graphs where each node is a number / tuple. 
`TiltedSquareLattice` has a `nodes_to_gridqubits` method which can provide a mapping from the graph nodes to the corresponding grid qubits.  
https://github.com/quantumlib/Cirq/blob/d42e05833953e1285f8175775e6ac5627709b926/cirq-core/cirq/devices/named_topologies.py#L233

This can be used to quickly get the graph needed for routing circuits from the topology graph as follows:
```python
routing_graph = nx.relabel_nodes(topology.graph, topology.nodes_to_gridqubits())
```


A similar convenience method, `nodes_to_linequbits`, should be added to the `LineQubit` named topology as well. 

cc @mpharrigan 


Discussion:
Yeah, I thought about this and almost included it in #4628 but omitted it because I figured it would be less useful for people putting stuff on gridqubit-based devices. 

It would be 
```python
return {i: q for i, q in enumerate(LineQubit.range(self.n)}
```

Resolving patch:
diff --git a/cirq-core/cirq/devices/named_topologies.py b/cirq-core/cirq/devices/named_topologies.py
--- a/cirq-core/cirq/devices/named_topologies.py
+++ b/cirq-core/cirq/devices/named_topologies.py
@@ -142,6 +142,14 @@ def draw(self, ax=None, tilted: bool = True, **kwargs) -> Dict[Any, Tuple[int, i
         g2 = nx.relabel_nodes(self.graph, {n: (n, 1) for n in self.graph.nodes})
         return draw_gridlike(g2, ax=ax, tilted=tilted, **kwargs)
 
+    def nodes_to_linequbits(self, offset: int = 0) -> Dict[int, 'cirq.LineQubit']:
+        """Return a mapping from graph nodes to `cirq.LineQubit`
+
+        Args:
+            offset: Offset integer positions of the resultant LineQubits by this amount.
+        """
+        return dict(enumerate(LineQubit.range(offset, offset + self.n_nodes)))
+
     def _json_dict_(self) -> Dict[str, Any]:
         return dataclass_json_dict(self)
 
@@ -240,8 +248,8 @@ def nodes_to_gridqubits(self, offset=(0, 0)) -> Dict[Tuple[int, int], 'cirq.Grid
         """Return a mapping from graph nodes to `cirq.GridQubit`
 
         Args:
-            offset: Offest row and column indices of the resultant GridQubits by this amount.
-                The offest positions the top-left node in the `draw(tilted=False)` frame.
+            offset: Offset row and column indices of the resultant GridQubits by this amount.
+                The offset positions the top-left node in the `draw(tilted=False)` frame.
         """
         return {(r, c): GridQubit(r, c) + offset for r, c in self.graph.nodes}
 


Test patch:
diff --git a/cirq-core/cirq/devices/named_topologies_test.py b/cirq-core/cirq/devices/named_topologies_test.py
--- a/cirq-core/cirq/devices/named_topologies_test.py
+++ b/cirq-core/cirq/devices/named_topologies_test.py
@@ -85,6 +85,11 @@ def test_line_topology():
     assert LineTopology(2).n_nodes == 2
     assert LineTopology(2).graph.number_of_nodes() == 2
 
+    mapping = topo.nodes_to_linequbits(offset=3)
+    assert sorted(mapping.keys()) == list(range(n))
+    assert all(isinstance(q, cirq.LineQubit) for q in mapping.values())
+    assert all(mapping[x] == cirq.LineQubit(x + 3) for x in mapping)
+
     cirq.testing.assert_equivalent_repr(topo)