Skip to content

Commit 32fe24e

Browse files
committed
Change qubit str representation
- Changes grid qubit string representation from (x, y) to q(x, y) and line qubit from 1 to q1. - This will make the string representation more distinctive. - Added _circuit_diagram_info_ for Qid objects to make circuit diagrams customizable for qubits. This allows us to keep circuit diagrams largely unchanged. - Other components such as pauli strings, that rely on qubit str representation for formatting are changed. This is a BREAKING CHANGE for anyone relying on string representation of qubits. Fixes: quantumlib#2405
1 parent b2f3d8a commit 32fe24e

12 files changed

+80
-39
lines changed

cirq-core/cirq/circuits/circuit.py

+6-2
Original file line numberDiff line numberDiff line change
@@ -1187,7 +1187,7 @@ def to_text_diagram_drawer(
11871187
Args:
11881188
use_unicode_characters: Determines if unicode characters are
11891189
allowed (as opposed to ascii-only diagrams).
1190-
qubit_namer: Names qubits in diagram. Defaults to str.
1190+
qubit_namer: Names qubits in diagram. Defaults to using _circuit_diagram_info_ or str.
11911191
transpose: Arranges qubit wires vertically instead of horizontally.
11921192
include_tags: Whether to include tags in the operation.
11931193
draw_moment_groups: Whether to draw moment symbol or not
@@ -1210,7 +1210,11 @@ def to_text_diagram_drawer(
12101210
label_map = {labels[i]: i for i in range(len(labels))}
12111211

12121212
def default_namer(label_entity):
1213-
return str(label_entity) + ('' if transpose else ': ')
1213+
try:
1214+
qubit_name = protocols.circuit_diagram_info(label_entity).wire_symbols[0]
1215+
except TypeError:
1216+
qubit_name = str(label_entity)
1217+
return qubit_name + ('' if transpose else ': ')
12141218

12151219
if qubit_namer is None:
12161220
qubit_namer = default_namer

cirq-core/cirq/devices/grid_qubit.py

+14-2
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,14 @@ def __repr__(self) -> str:
254254
return f"cirq.GridQid({self.row}, {self.col}, dimension={self.dimension})"
255255

256256
def __str__(self) -> str:
257-
return f"({self.row}, {self.col}) (d={self.dimension})"
257+
return f"q({self.row}, {self.col}) (d={self.dimension})"
258+
259+
def _circuit_diagram_info_(
260+
self, args: 'cirq.CircuitDiagramInfoArgs'
261+
) -> 'cirq.CircuitDiagramInfo':
262+
return protocols.CircuitDiagramInfo(
263+
wire_symbols=(f"({self.row}, {self.col}) (d={self.dimension})",)
264+
)
258265

259266
def _json_dict_(self) -> Dict[str, Any]:
260267
return protocols.obj_to_dict_helper(self, ['row', 'col', 'dimension'])
@@ -403,7 +410,12 @@ def __repr__(self) -> str:
403410
return f"cirq.GridQubit({self.row}, {self.col})"
404411

405412
def __str__(self) -> str:
406-
return f"({self.row}, {self.col})"
413+
return f"q({self.row}, {self.col})"
414+
415+
def _circuit_diagram_info_(
416+
self, args: 'cirq.CircuitDiagramInfoArgs'
417+
) -> 'cirq.CircuitDiagramInfo':
418+
return protocols.CircuitDiagramInfo(wire_symbols=(f"({self.row}, {self.col})",))
407419

408420
def _json_dict_(self) -> Dict[str, Any]:
409421
return protocols.obj_to_dict_helper(self, ['row', 'col'])

cirq-core/cirq/devices/grid_qubit_test.py

+11-2
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,17 @@ def test_pickled_hash():
5353

5454

5555
def test_str():
56-
assert str(cirq.GridQubit(5, 2)) == '(5, 2)'
57-
assert str(cirq.GridQid(5, 2, dimension=3)) == '(5, 2) (d=3)'
56+
assert str(cirq.GridQubit(5, 2)) == 'q(5, 2)'
57+
assert str(cirq.GridQid(5, 2, dimension=3)) == 'q(5, 2) (d=3)'
58+
59+
60+
def test_circuit_info():
61+
assert cirq.circuit_diagram_info(cirq.GridQubit(5, 2)) == cirq.CircuitDiagramInfo(
62+
wire_symbols=('(5, 2)',)
63+
)
64+
assert cirq.circuit_diagram_info(cirq.GridQid(5, 2, dimension=3)) == cirq.CircuitDiagramInfo(
65+
wire_symbols=('(5, 2) (d=3)',)
66+
)
5867

5968

6069
def test_repr():

cirq-core/cirq/devices/line_qubit.py

+12-2
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,12 @@ def __repr__(self) -> str:
190190
return f"cirq.LineQid({self.x}, dimension={self.dimension})"
191191

192192
def __str__(self) -> str:
193-
return f"{self.x} (d={self.dimension})"
193+
return f"q{self.x} (d={self.dimension})"
194+
195+
def _circuit_diagram_info_(
196+
self, args: 'cirq.CircuitDiagramInfoArgs'
197+
) -> 'cirq.CircuitDiagramInfo':
198+
return protocols.CircuitDiagramInfo(wire_symbols=(f"{self.x} (d={self.dimension})",))
194199

195200
def _json_dict_(self) -> Dict[str, Any]:
196201
return protocols.obj_to_dict_helper(self, ['x', 'dimension'])
@@ -241,7 +246,12 @@ def __repr__(self) -> str:
241246
return f"cirq.LineQubit({self.x})"
242247

243248
def __str__(self) -> str:
244-
return f"{self.x}"
249+
return f"q{self.x}"
250+
251+
def _circuit_diagram_info_(
252+
self, args: 'cirq.CircuitDiagramInfoArgs'
253+
) -> 'cirq.CircuitDiagramInfo':
254+
return protocols.CircuitDiagramInfo(wire_symbols=(f"{self.x}",))
245255

246256
def _json_dict_(self) -> Dict[str, Any]:
247257
return protocols.obj_to_dict_helper(self, ['x'])

cirq-core/cirq/devices/line_qubit_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ def test_eq():
3535

3636

3737
def test_str():
38-
assert str(cirq.LineQubit(5)) == '5'
39-
assert str(cirq.LineQid(5, dimension=3)) == '5 (d=3)'
38+
assert str(cirq.LineQubit(5)) == 'q5'
39+
assert str(cirq.LineQid(5, dimension=3)) == 'q5 (d=3)'
4040

4141

4242
def test_repr():

cirq-core/cirq/ops/classically_controlled_operation_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,7 @@ def test_qasm():
208208
include "qelib1.inc";
209209
210210
211-
// Qubits: [0, 1]
211+
// Qubits: [q0, q1]
212212
qreg q[2];
213213
creg m_a[1];
214214
@@ -416,7 +416,7 @@ def test_decompose():
416416
def test_str():
417417
q0 = cirq.LineQubit(0)
418418
op = cirq.X(q0).with_classical_controls('a')
419-
assert str(op) == 'X(0).with_classical_controls(a)'
419+
assert str(op) == 'X(q0).with_classical_controls(a)'
420420

421421

422422
def test_scope_local():

cirq-core/cirq/ops/controlled_gate_test.py

+7-7
Original file line numberDiff line numberDiff line change
@@ -514,11 +514,11 @@ def test_circuit_diagram():
514514
cirq.testing.assert_has_diagram(
515515
c,
516516
"""
517-
0: ───@──────
517+
0: ───@──────
518518
519-
1: ───H(1)───
519+
1: ───H(q1)───
520520
521-
2: ───H(2)───
521+
2: ───H(q2)───
522522
""",
523523
)
524524

@@ -530,13 +530,13 @@ def test_circuit_diagram():
530530
cirq.testing.assert_has_diagram(
531531
c,
532532
"""
533-
0 (d=3): ───@────────────
533+
0 (d=3): ───@────────────
534534
535-
1 (d=3): ───(0,1)────────
535+
1 (d=3): ───(0,1)────────
536536
537-
2 (d=3): ───(0,2)────────
537+
2 (d=3): ───(0,2)────────
538538
539-
3 (d=2): ───H(3 (d=2))───
539+
3 (d=2): ───H(q3 (d=2))───
540540
""",
541541
)
542542

cirq-core/cirq/ops/controlled_operation_test.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -233,11 +233,11 @@ def test_circuit_diagram():
233233
cirq.testing.assert_has_diagram(
234234
c,
235235
"""
236-
0: ───@──────
236+
0: ───@──────
237237
238-
1: ───H(1)───
238+
1: ───H(q1)───
239239
240-
2: ───H(2)───
240+
2: ───H(q2)───
241241
""",
242242
)
243243

@@ -247,11 +247,11 @@ def test_circuit_diagram():
247247
cirq.testing.assert_has_diagram(
248248
c,
249249
"""
250-
0: ───@──────
250+
0: ───@──────
251251
252-
1: ───@──────
252+
1: ───@──────
253253
254-
2: ───H(2)───
254+
2: ───H(q2)───
255255
""",
256256
)
257257

@@ -266,13 +266,13 @@ def test_circuit_diagram():
266266
cirq.testing.assert_has_diagram(
267267
c,
268268
"""
269-
0 (d=3): ───@────────────
269+
0 (d=3): ───@────────────
270270
271-
1 (d=3): ───(0,1)────────
271+
1 (d=3): ───(0,1)────────
272272
273-
2 (d=3): ───(0,2)────────
273+
2 (d=3): ───(0,2)────────
274274
275-
3 (d=2): ───H(3 (d=2))───
275+
3 (d=2): ───H(q3 (d=2))───
276276
""",
277277
)
278278

cirq-core/cirq/ops/linear_combinations_test.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -984,16 +984,16 @@ def test_add_number_paulistring():
984984
def test_pauli_sum_formatting():
985985
q = cirq.LineQubit.range(2)
986986
pauli = cirq.X(q[0])
987-
assert str(pauli) == 'X(0)'
987+
assert str(pauli) == 'X(q0)'
988988
paulistr = cirq.X(q[0]) * cirq.X(q[1])
989-
assert str(paulistr) == 'X(0)*X(1)'
989+
assert str(paulistr) == 'X(q0)*X(q1)'
990990
paulisum1 = cirq.X(q[0]) * cirq.X(q[1]) + 4
991-
assert str(paulisum1) == '1.000*X(0)*X(1)+4.000*I'
991+
assert str(paulisum1) == '1.000*X(q0)*X(q1)+4.000*I'
992992
paulisum2 = cirq.X(q[0]) * cirq.X(q[1]) + cirq.Z(q[0])
993-
assert str(paulisum2) == '1.000*X(0)*X(1)+1.000*Z(0)'
993+
assert str(paulisum2) == '1.000*X(q0)*X(q1)+1.000*Z(q0)'
994994
paulisum3 = cirq.X(q[0]) * cirq.X(q[1]) + cirq.Z(q[0]) * cirq.Z(q[1])
995-
assert str(paulisum3) == '1.000*X(0)*X(1)+1.000*Z(0)*Z(1)'
996-
assert f"{paulisum3:.0f}" == '1*X(0)*X(1)+1*Z(0)*Z(1)'
995+
assert str(paulisum3) == '1.000*X(q0)*X(q1)+1.000*Z(q0)*Z(q1)'
996+
assert f"{paulisum3:.0f}" == '1*X(q0)*X(q1)+1*Z(q0)*Z(q1)'
997997

998998
empty = cirq.PauliSum.from_pauli_strings([])
999999
assert str(empty) == "0.000"

cirq-core/cirq/ops/pauli_string_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1568,7 +1568,7 @@ def text(self, to_print):
15681568

15691569
p = FakePrinter()
15701570
result._repr_pretty_(p, False)
1571-
assert p.text_pretty == 'X(0)*Y(1)*Z(2)'
1571+
assert p.text_pretty == 'X(q0)*Y(q1)*Z(q2)'
15721572

15731573
# Test cycle handling
15741574
p = FakePrinter()
@@ -1874,7 +1874,7 @@ def test_mutable_pauli_string_dict_pauli_like_not_pauli_like():
18741874
def test_mutable_pauli_string_text():
18751875
p = cirq.MutablePauliString(cirq.X(cirq.LineQubit(0)) * cirq.Y(cirq.LineQubit(1)))
18761876
assert str(cirq.MutablePauliString()) == "mutable I"
1877-
assert str(p) == "mutable X(0)*Y(1)"
1877+
assert str(p) == "mutable X(q0)*Y(q1)"
18781878
cirq.testing.assert_equivalent_repr(p)
18791879

18801880

cirq-core/cirq/ops/pauli_sum_exponential_test.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -149,11 +149,11 @@ def test_pauli_sum_exponential_repr(psum_exp):
149149
(cirq.PauliSumExponential(0, np.pi / 2), 'exp(j * 1.5707963267948966 * (0.000))'),
150150
(
151151
cirq.PauliSumExponential(2j * cirq.X(q0) + 4j * cirq.Y(q1), 2),
152-
'exp(2 * (2.000j*X(0)+4.000j*Y(1)))',
152+
'exp(2 * (2.000j*X(q0)+4.000j*Y(q1)))',
153153
),
154154
(
155155
cirq.PauliSumExponential(0.5 * cirq.X(q0) + 0.6 * cirq.Y(q1), sympy.Symbol("theta")),
156-
'exp(j * theta * (0.500*X(0)+0.600*Y(1)))',
156+
'exp(j * theta * (0.500*X(q0)+0.600*Y(q1)))',
157157
),
158158
),
159159
)

cirq-core/cirq/ops/raw_types.py

+6
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,12 @@ def __ge__(self, other):
140140
return NotImplemented
141141
return self._cmp_tuple() >= other._cmp_tuple()
142142

143+
def _circuit_diagram_info_(
144+
self, args: 'cirq.CircuitDiagramInfoArgs'
145+
) -> 'cirq.CircuitDiagramInfo':
146+
"""Circuit symbol for qids defaults to the string representation."""
147+
return protocols.CircuitDiagramInfo(wire_symbols=(str(self),))
148+
143149

144150
@functools.total_ordering
145151
class _QubitAsQid(Qid):

0 commit comments

Comments
 (0)