Repository: quantumlib/Cirq

Issue:
Add whether a diagram is transposed to CircuitDiagramInfoArgs 
- Whether or not the diagram is transposed.
- The relative positioning of the qubits (e.g. so you can determine if they are adjacent and/or in order).


Discussion:
The second of these has been addressed.

Resolving patch:
diff --git a/cirq-core/cirq/circuits/circuit.py b/cirq-core/cirq/circuits/circuit.py
--- a/cirq-core/cirq/circuits/circuit.py
+++ b/cirq-core/cirq/circuits/circuit.py
@@ -1241,6 +1241,7 @@ def default_namer(label_entity):
                 get_circuit_diagram_info=get_circuit_diagram_info,
                 include_tags=include_tags,
                 first_annotation_row=first_annotation_row,
+                transpose=transpose,
             )
 
         w = diagram.width()
@@ -2376,6 +2377,7 @@ def _draw_moment_annotations(
     ],
     include_tags: bool,
     first_annotation_row: int,
+    transpose: bool,
 ):
 
     for k, annotation in enumerate(_get_moment_annotations(moment)):
@@ -2386,6 +2388,7 @@ def _draw_moment_annotations(
             label_map=label_map,
             precision=precision,
             include_tags=include_tags,
+            transpose=transpose,
         )
         info = get_circuit_diagram_info(annotation, args)
         symbols = info._wire_symbols_including_formatted_exponent(args)
@@ -2407,6 +2410,7 @@ def _draw_moment_in_diagram(
     ],
     include_tags: bool,
     first_annotation_row: int,
+    transpose: bool,
 ):
     if get_circuit_diagram_info is None:
         get_circuit_diagram_info = circuit_diagram_info_protocol._op_info_with_fallback
@@ -2436,6 +2440,7 @@ def _draw_moment_in_diagram(
             label_map=label_map,
             precision=precision,
             include_tags=include_tags,
+            transpose=transpose,
         )
         info = get_circuit_diagram_info(op, args)
 
@@ -2464,6 +2469,7 @@ def _draw_moment_in_diagram(
         get_circuit_diagram_info=get_circuit_diagram_info,
         include_tags=include_tags,
         first_annotation_row=first_annotation_row,
+        transpose=transpose,
     )
 
     global_phase, tags = _get_global_phase_and_tags_for_ops(moment)
diff --git a/cirq-core/cirq/protocols/circuit_diagram_info_protocol.py b/cirq-core/cirq/protocols/circuit_diagram_info_protocol.py
--- a/cirq-core/cirq/protocols/circuit_diagram_info_protocol.py
+++ b/cirq-core/cirq/protocols/circuit_diagram_info_protocol.py
@@ -192,7 +192,9 @@ class CircuitDiagramInfoArgs:
         precision: The number of digits after the decimal to show for numbers in
             the text diagram. None means use full precision.
         label_map: The map from label entities to diagram positions.
-        include_tags: Whether to print tags from TaggedOperations
+        include_tags: Whether to print tags from TaggedOperations.
+        transpose: Whether the circuit is to be drawn with time from left to
+            right (transpose is False), or from top to bottom.
     """
 
     UNINFORMED_DEFAULT: 'CircuitDiagramInfoArgs'
@@ -205,6 +207,7 @@ def __init__(
         precision: Optional[int],
         label_map: Optional[Dict['cirq.LabelEntity', int]],
         include_tags: bool = True,
+        transpose: bool = False,
     ) -> None:
         self.known_qubits = None if known_qubits is None else tuple(known_qubits)
         self.known_qubit_count = known_qubit_count
@@ -212,6 +215,7 @@ def __init__(
         self.precision = precision
         self.label_map = label_map
         self.include_tags = include_tags
+        self.transpose = transpose
 
     def _value_equality_values_(self) -> Any:
         return (
@@ -223,6 +227,7 @@ def _value_equality_values_(self) -> Any:
             if self.label_map is None
             else tuple(sorted(self.label_map.items(), key=lambda e: e[0])),
             self.include_tags,
+            self.transpose,
         )
 
     def __repr__(self) -> str:
@@ -232,8 +237,9 @@ def __repr__(self) -> str:
             f'known_qubit_count={self.known_qubit_count!r}, '
             f'use_unicode_characters={self.use_unicode_characters!r}, '
             f'precision={self.precision!r}, '
-            f'label_map={self.label_map!r},'
-            f'include_tags={self.include_tags!r})'
+            f'label_map={self.label_map!r}, '
+            f'include_tags={self.include_tags!r}, '
+            f'transpose={self.transpose!r})'
         )
 
     def format_real(self, val: Union[sympy.Basic, int, float]) -> str:
@@ -280,6 +286,7 @@ def copy(self):
             use_unicode_characters=self.use_unicode_characters,
             precision=self.precision,
             label_map=self.label_map,
+            transpose=self.transpose,
         )
 
     def with_args(self, **kwargs):
@@ -295,6 +302,7 @@ def with_args(self, **kwargs):
     use_unicode_characters=True,
     precision=3,
     label_map=None,
+    transpose=False,
 )
 
 


Test patch:
diff --git a/cirq-core/cirq/circuits/circuit_test.py b/cirq-core/cirq/circuits/circuit_test.py
--- a/cirq-core/cirq/circuits/circuit_test.py
+++ b/cirq-core/cirq/circuits/circuit_test.py
@@ -2749,6 +2749,30 @@ def test_transposed_diagram_exponent_order(circuit_cls):
     )
 
 
+@pytest.mark.parametrize('circuit_cls', [cirq.Circuit, cirq.FrozenCircuit])
+def test_transposed_diagram_can_depend_on_transpose(circuit_cls):
+    class TestGate(cirq.Gate):
+        def num_qubits(self):
+            return 1
+
+        def _circuit_diagram_info_(self, args):
+            return cirq.CircuitDiagramInfo(wire_symbols=("t" if args.transpose else "r",))
+
+    c = cirq.Circuit(TestGate()(cirq.NamedQubit("a")))
+
+    cirq.testing.assert_has_diagram(c, "a: ───r───")
+    cirq.testing.assert_has_diagram(
+        c,
+        """
+a
+│
+t
+│
+""",
+        transpose=True,
+    )
+
+
 def test_insert_moments():
     q = cirq.NamedQubit('q')
     c = cirq.Circuit()
diff --git a/cirq-core/cirq/protocols/circuit_diagram_info_protocol_test.py b/cirq-core/cirq/protocols/circuit_diagram_info_protocol_test.py
--- a/cirq-core/cirq/protocols/circuit_diagram_info_protocol_test.py
+++ b/cirq-core/cirq/protocols/circuit_diagram_info_protocol_test.py
@@ -173,6 +173,16 @@ def test_circuit_diagram_info_args_eq():
             label_map={cirq.LineQubit(0): 5, cirq.LineQubit(1): 7},
         )
     )
+    eq.add_equality_group(
+        cirq.CircuitDiagramInfoArgs(
+            known_qubits=cirq.LineQubit.range(2),
+            known_qubit_count=2,
+            use_unicode_characters=False,
+            precision=None,
+            label_map={cirq.LineQubit(0): 5, cirq.LineQubit(1): 7},
+            transpose=True,
+        )
+    )
 
 
 def test_circuit_diagram_info_args_repr():
@@ -184,6 +194,7 @@ def test_circuit_diagram_info_args_repr():
             precision=5,
             label_map={cirq.LineQubit(0): 5, cirq.LineQubit(1): 7},
             include_tags=False,
+            transpose=True,
         )
     )