Skip to content

Commit 21e4f07

Browse files
authored
Refactor AsciiDiagrammableGate into TextDiagrammableGate (#293)
- Find all places where docs/code says "ASCII" and replace it with "text" as appropriate - Split to_text_diagram_drawer out of circuit.to_text_diagram - Rename ascii_wire_symbols to text_diagram_wire_symbols - Rename ascii_exponent to text_diagram_exponent - Add optional qubit_count argument to text_diagram_wire_symbols - Add optional use_unicode_characters argument to text_diagram_wire_symbols - Remove unused XmonQubit try_parse_from_text method
1 parent f32a262 commit 21e4f07

File tree

11 files changed

+149
-78
lines changed

11 files changed

+149
-78
lines changed

cirq/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,6 @@
7878
)
7979

8080
from cirq.ops import (
81-
AsciiDiagrammableGate,
8281
BoundedEffectGate,
8382
CNOT,
8483
CNotGate,
@@ -112,6 +111,7 @@
112111
SWAP,
113112
SwapGate,
114113
T,
114+
TextDiagrammableGate,
115115
transform_op_tree,
116116
TwoQubitGate,
117117
TwoQubitMatrixGate,

cirq/circuits/circuit.py

Lines changed: 50 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -402,10 +402,10 @@ def to_text_diagram(
402402
"""Returns text containing a diagram describing the circuit.
403403
404404
Args:
405-
ext: For extending gates to implement AsciiDiagrammableGate.
406-
use_unicode_characters: Activates the use of cleaner-looking
407-
unicode box-drawing characters for lines.
408-
transpose: Arranges the wires vertically instead of horizontally.
405+
ext: For extending gates to implement TextDiagrammableGate.
406+
use_unicode_characters: Determines if unicode characters are
407+
allowed (as opposed to ascii-only diagrams).
408+
transpose: Arranges qubit wires vertically instead of horizontally.
409409
qubit_order_key: Transforms each qubit into a key that determines
410410
how the qubits are ordered in the diagram. Qubits with lower
411411
keys come first. Defaults to the qubit's __str__, but augmented
@@ -414,7 +414,43 @@ def to_text_diagram(
414414
"name2").
415415
416416
Returns:
417-
The ascii diagram.
417+
The text diagram.
418+
"""
419+
420+
diagram = self.to_text_diagram_drawer(
421+
ext=ext,
422+
qubit_name_suffix='' if transpose else ': ',
423+
qubit_order_key=qubit_order_key)
424+
425+
if transpose:
426+
return diagram.transpose().render(
427+
crossing_char='─' if use_unicode_characters else '-',
428+
use_unicode_characters=use_unicode_characters)
429+
return diagram.render(
430+
crossing_char='┼' if use_unicode_characters else '|',
431+
horizontal_spacing=3,
432+
use_unicode_characters=use_unicode_characters)
433+
434+
def to_text_diagram_drawer(
435+
self,
436+
ext: Extensions = Extensions(),
437+
qubit_name_suffix: str = '',
438+
qubit_order_key: Callable[[QubitId], Any] = None
439+
) -> TextDiagramDrawer:
440+
"""Returns a TextDiagramDrawer with the circuit drawn into it.
441+
442+
Args:
443+
ext: For extending gates to implement TextDiagrammableGate.
444+
qubit_name_suffix: Appended to qubit names in the diagram.
445+
qubit_order_key: Transforms each qubit into a key that determines
446+
how the qubits are ordered in the diagram. Qubits with lower
447+
keys come first. Defaults to the qubit's __str__, but augmented
448+
so that lexicographic ordering will respect the order of
449+
integers within the string (e.g. "name10" will come after
450+
"name2").
451+
452+
Returns:
453+
The TextDiagramDrawer instance.
418454
"""
419455
if qubit_order_key is None:
420456
qubit_order_key = _str_lexicographic_respecting_int_order
@@ -432,7 +468,7 @@ def to_text_diagram(
432468

433469
diagram = TextDiagramDrawer()
434470
for q, i in qubit_map.items():
435-
diagram.write(0, i, str(q) + ('' if transpose else ': '))
471+
diagram.write(0, i, str(q) + qubit_name_suffix)
436472

437473
for moment in [Moment()] * 2 + self.moments + [Moment()]:
438474
_draw_moment_in_diagram(moment, ext, qubit_map, diagram)
@@ -441,28 +477,21 @@ def to_text_diagram(
441477
for i in qubit_map.values():
442478
diagram.horizontal_line(i, 0, w)
443479

444-
if transpose:
445-
return diagram.transpose().render(
446-
crossing_char='─' if use_unicode_characters else '-',
447-
use_unicode_characters=use_unicode_characters)
448-
return diagram.render(
449-
crossing_char='┼' if use_unicode_characters else '|',
450-
horizontal_spacing=3,
451-
use_unicode_characters=use_unicode_characters)
480+
return diagram
452481

453482

454483
def _get_operation_text_diagram_symbols(op: ops.Operation, ext: Extensions
455484
) -> Iterable[str]:
456-
ascii_gate = ext.try_cast(op.gate, ops.AsciiDiagrammableGate)
457-
if ascii_gate is not None:
458-
wire_symbols = ascii_gate.ascii_wire_symbols()
485+
text_diagram_gate = ext.try_cast(op.gate, ops.TextDiagrammableGate)
486+
if text_diagram_gate is not None:
487+
wire_symbols = text_diagram_gate.text_diagram_wire_symbols()
459488
if len(op.qubits) == len(wire_symbols):
460489
return wire_symbols
461490
elif len(wire_symbols) == 1:
462491
return len(op.qubits) * wire_symbols
463492
else:
464493
raise ValueError(
465-
'Multi-qubit operation with AsciiDiagrammableGate {} that '
494+
'Multi-qubit operation with TextDiagrammableGate {} that '
466495
'requires {} qubits but found {} qubits'.format(
467496
repr(op.gate), len(wire_symbols), len(op.qubits)))
468497

@@ -474,10 +503,10 @@ def _get_operation_text_diagram_symbols(op: ops.Operation, ext: Extensions
474503

475504
def _get_operation_text_diagram_exponent(op: ops.Operation,
476505
ext: Extensions) -> Optional[str]:
477-
ascii_gate = ext.try_cast(op.gate, ops.AsciiDiagrammableGate)
478-
if ascii_gate is None:
506+
text_diagram_gate = ext.try_cast(op.gate, ops.TextDiagrammableGate)
507+
if text_diagram_gate is None:
479508
return None
480-
exponent = ascii_gate.ascii_exponent()
509+
exponent = text_diagram_gate.text_diagram_exponent()
481510
if exponent == 1:
482511
return None
483512
if isinstance(exponent, float):

cirq/circuits/circuit_test.py

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -581,16 +581,18 @@ def __repr__(self):
581581
""".strip()
582582

583583
# Succeeds with extension.
584-
class FGateAsAscii(ops.AsciiDiagrammableGate):
584+
class FGateAsText(ops.TextDiagrammableGate):
585585
def __init__(self, f_gate):
586586
self.f_gate = f_gate
587587

588-
def ascii_wire_symbols(self):
588+
def text_diagram_wire_symbols(self,
589+
qubit_count=None,
590+
use_unicode_characters=True):
589591
return 'F'
590592

591593
diagram = c.to_text_diagram(Extensions({
592-
ops.AsciiDiagrammableGate: {
593-
FGate: FGateAsAscii
594+
ops.TextDiagrammableGate: {
595+
FGate: FGateAsText
594596
}
595597
}), use_unicode_characters=False)
596598

@@ -627,8 +629,10 @@ def test_to_text_diagram_multi_qubit_gate():
627629

628630

629631
def test_to_text_diagram_many_qubits_gate_but_multiple_wire_symbols():
630-
class BadGate(ops.AsciiDiagrammableGate):
631-
def ascii_wire_symbols(self):
632+
class BadGate(ops.TextDiagrammableGate):
633+
def text_diagram_wire_symbols(self,
634+
qubit_count=None,
635+
use_unicode_characters=True):
632636
return 'a', 'a'
633637
q1 = ops.NamedQubit('(0, 0)')
634638
q2 = ops.NamedQubit('(0, 1)')
@@ -641,14 +645,16 @@ def ascii_wire_symbols(self):
641645
def test_to_text_diagram_parameterized_value():
642646
q = ops.NamedQubit('cube')
643647

644-
class PGate(ops.AsciiDiagrammableGate):
648+
class PGate(ops.TextDiagrammableGate):
645649
def __init__(self, val):
646650
self.val = val
647651

648-
def ascii_wire_symbols(self):
652+
def text_diagram_wire_symbols(self,
653+
qubit_count=None,
654+
use_unicode_characters=True):
649655
return 'P',
650656

651-
def ascii_exponent(self):
657+
def text_diagram_exponent(self):
652658
return self.val
653659

654660
c = Circuit.from_ops(

cirq/circuits/text_diagram_drawer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ def render(self,
9393
vertical_spacing: int = 1,
9494
crossing_char: str = None,
9595
use_unicode_characters: bool = True) -> str:
96-
"""Outputs ascii text containing the ascii diagram."""
96+
"""Outputs text containing the diagram."""
9797

9898
pipe = '│' if use_unicode_characters else '|'
9999
dash = '─' if use_unicode_characters else '-'

cirq/docs/circuits.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ moment1 = cirq.circuits.Moment([cz12])
8282
circuit = cirq.circuits.Circuit((moment0, moment1))
8383

8484
print(circuit)
85-
# prints the ascii diagram for the circuit:
85+
# prints the text diagram for the circuit:
8686
# (0, 0): ───Z───────
8787
#
8888
# (0, 1): ───Z───Z───

cirq/docs/gates.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -102,12 +102,12 @@ take an ``Extension`` which allows for overriding the
102102
``CompositeGate``. An example of this is for in
103103
``Simulators`` where an optional
104104

105-
#### AsciiDiagramableGate
105+
#### TextDiagrammableGate
106106

107-
Ascii diagrams of ``Circuits`` are actually quite useful for
108-
visualizing the moment structure of a ``Circuit``. In order
109-
for this to display in a compact form, it is best practice
110-
to implement his feature.
107+
Text diagrams of ``Circuits`` are actually quite useful for
108+
visualizing the moment structure of a ``Circuit``. Gates that
109+
implement this feature can specify compact representations to
110+
use in the diagram (e.g. '×' instead of 'SWAP').
111111

112112
### XmonGates
113113

cirq/google/xmon_gates.py

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ def __repr__(self):
104104

105105

106106
class Exp11Gate(XmonGate,
107-
ops.AsciiDiagrammableGate,
107+
ops.TextDiagrammableGate,
108108
ops.InterchangeableQubitsGate,
109109
ops.PhaseableGate,
110110
PotentialImplementation):
@@ -142,10 +142,12 @@ def matrix(self):
142142
raise ValueError("Don't have a known matrix.")
143143
return ops.Rot11Gate(half_turns=self.half_turns).matrix()
144144

145-
def ascii_wire_symbols(self):
145+
def text_diagram_wire_symbols(self,
146+
qubit_count=None,
147+
use_unicode_characters=True):
146148
return 'Z', 'Z'
147149

148-
def ascii_exponent(self):
150+
def text_diagram_exponent(self):
149151
return self.half_turns
150152

151153
def __str__(self):
@@ -171,7 +173,7 @@ def __hash__(self):
171173

172174
class ExpWGate(XmonGate,
173175
ops.SingleQubitGate,
174-
ops.AsciiDiagrammableGate,
176+
ops.TextDiagrammableGate,
175177
ops.PhaseableGate,
176178
ops.BoundedEffectGate,
177179
PotentialImplementation):
@@ -242,18 +244,20 @@ def trace_distance_bound(self):
242244
return 1
243245
return abs(self.half_turns) * 3.5
244246

245-
def ascii_wire_symbols(self):
247+
def text_diagram_wire_symbols(self,
248+
qubit_count=None,
249+
use_unicode_characters=True):
246250
if self.axis_half_turns == 0:
247251
return 'X',
248252
if self.axis_half_turns == 0.5:
249253
return 'Y',
250254
return 'W({})'.format(self.axis_half_turns),
251255

252-
def ascii_exponent(self):
256+
def text_diagram_exponent(self):
253257
return self.half_turns
254258

255259
def __str__(self):
256-
base = self.ascii_wire_symbols()[0]
260+
base = self.text_diagram_wire_symbols()[0]
257261
if self.half_turns == 1:
258262
return base
259263
return '{}^{}'.format(base, self.half_turns)
@@ -288,7 +292,7 @@ def __hash__(self):
288292

289293
class ExpZGate(XmonGate,
290294
ops.SingleQubitGate,
291-
ops.AsciiDiagrammableGate,
295+
ops.TextDiagrammableGate,
292296
PotentialImplementation):
293297
"""A rotation around the Z axis of the Bloch sphere."""
294298

@@ -297,14 +301,16 @@ def __init__(self, *positional_args,
297301
assert not positional_args
298302
self.half_turns = _canonicalize_half_turns(half_turns)
299303

300-
def ascii_wire_symbols(self):
304+
def text_diagram_wire_symbols(self,
305+
qubit_count=None,
306+
use_unicode_characters=True):
301307
if self.half_turns in [-0.25, 0.25]:
302308
return 'T'
303309
if self.half_turns in [-0.5, 0.5]:
304310
return 'S'
305311
return 'Z',
306312

307-
def ascii_exponent(self):
313+
def text_diagram_exponent(self):
308314
if self.half_turns in [0.25, 0.5]:
309315
return 1
310316
if self.half_turns in [-0.5, -0.25]:

cirq/google/xmon_qubit.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,6 @@
1111
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
14-
import re
1514

1615
from cirq.api.google.v1 import operations_pb2
1716
from cirq.ops import QubitId
@@ -44,13 +43,6 @@ def __repr__(self):
4443
def __str__(self):
4544
return '({}, {})'.format(self.row, self.col)
4645

47-
@staticmethod
48-
def try_parse_from_ascii(text):
49-
if re.match('\\(\\s*\\d+,\\s*\\d+\\s*\\)', text):
50-
a, b = text[1:-1].split(',')
51-
return XmonQubit(int(a.strip()), int(b.strip()))
52-
return None
53-
5446
def to_proto(
5547
self, out: operations_pb2.Qubit = None) -> operations_pb2.Qubit:
5648
"""Return the proto form, mutating supplied form if supplied."""

cirq/ops/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
Z,
3636
)
3737
from cirq.ops.gate_features import (
38-
AsciiDiagrammableGate,
3938
BoundedEffectGate,
4039
CompositeGate,
4140
ExtrapolatableGate,
@@ -44,6 +43,7 @@
4443
ReversibleGate,
4544
SelfInverseGate,
4645
SingleQubitGate,
46+
TextDiagrammableGate,
4747
TwoQubitGate,
4848
)
4949
from cirq.ops.matrix_gates import (

0 commit comments

Comments
 (0)