Repository: quantumlib/Cirq

Issue:
Missing moment indicators in circuit diagram
This code:

```python
import cirq.experiments
print(cirq.experiments.generate_supremacy_circuit_google_v2_grid(
    n_rows=4,
    n_cols=5,
    cz_depth=20,
    seed=1
).to_text_diagram(transpose=True))
```

Produces this diagram:

```
  (0, 0) (0, 1) (0, 2) (0, 3) (0, 4) (1, 0) (1, 1) (1, 2) (1, 3) (1, 4) (2, 0) (2, 1) (2, 2) (2, 3) (2, 4) (3, 0) (3, 1) (3, 2) (3, 3) (3, 4)
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  @──────@      T      T      T      T      T      @──────@      T      @──────@      T      T      T      T      T      @──────@      T
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  X^0.5  Y^0.5  │      │      │      @──────┼──────┼──────┼──────┼──────@      X^0.5  │      │      │      │      │      X^0.5  X^0.5  │
  │      │      │      │      │      │      │      │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │
  │      │      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  T      @──────@      │      │      Y^0.5  │      Y^0.5  @──────@      X^0.5  @──────@      │      X^0.5  │      │      T      @──────@
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      X^0.5  │      T      │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      X^0.5
  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │
  │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      T      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  X^0.5  T      @──────@      Y^0.5  @──────@      X^0.5  T      Y^0.5  │      Y^0.5  @──────@      │      @──────@      │      X^0.5  T
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  T      │      X^0.5  Y^0.5  T      Y^0.5  @──────┼──────┼──────┼──────┼──────@      X^0.5  │      │      X^0.5  X^0.5  │      T      │
  │      │      │      │      │      │      │      T      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      T      │      │      │      │      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      │      T      @──────@      T      @──────@      X^0.5  │      │      X^0.5  T      @──────@      T      @──────@      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
┌╴│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │     ╶┐
│ │      @──────┼──────┼──────┼──────┼──────@      X^0.5  │      │      │      T      │      X^0.5  @──────┼──────┼──────┼──────┼──────@      │
│ │      │      │      @──────┼──────┼──────┼──────┼──────@      │      @──────┼──────┼──────┼──────┼──────@      X^0.5  │      │      │      │
└╴│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │     ╶┘
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      │      │      │      X^0.5  │      │      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  @──────@      │      X^0.5  T      │      X^0.5  @──────@      │      @──────@      X^0.5  T      X^0.5  Y^0.5  T      @──────@      Y^0.5
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  Y^0.5  X^0.5  │      T      │      @──────┼──────┼──────┼──────┼──────@      Y^0.5  │      │      │      T      │      X^0.5  X^0.5  T
  │      │      │      │      │      │      T      │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │
  │      │      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  T      @──────@      │      │      Y^0.5  │      Y^0.5  @──────@      Y^0.5  @──────@      │      X^0.5  │      │      T      @──────@
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      Y^0.5  │      T      │      X^0.5  @──────┼──────┼──────┼──────┼──────@      Y^0.5
  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │
  │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      T      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  Y^0.5  T      @──────@      Y^0.5  @──────@      Y^0.5  T      Y^0.5  │      X^0.5  @──────@      │      @──────@      │      X^0.5  T
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  T      │      Y^0.5  X^0.5  T      X^0.5  @──────┼──────┼──────┼──────┼──────@      Y^0.5  │      │      Y^0.5  Y^0.5  │      T      │
  │      │      │      │      │      │      │      T      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      T      │      │      │      │      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      │      T      @──────@      T      @──────@      X^0.5  │      │      X^0.5  T      @──────@      T      @──────@      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
┌╴│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │     ╶┐
│ │      @──────┼──────┼──────┼──────┼──────@      Y^0.5  │      │      │      T      │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      │
│ │      │      │      @──────┼──────┼──────┼──────┼──────@      │      @──────┼──────┼──────┼──────┼──────@      X^0.5  │      │      │      │
└╴│      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │     ╶┘
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      │      │      │      Y^0.5  │      │      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  @──────@      │      X^0.5  T      │      X^0.5  @──────@      │      @──────@      X^0.5  T      Y^0.5  Y^0.5  T      @──────@      Y^0.5
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  X^0.5  X^0.5  │      T      │      @──────┼──────┼──────┼──────┼──────@      Y^0.5  │      │      │      T      │      Y^0.5  Y^0.5  T
  │      │      │      │      │      │      T      │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │
  │      │      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  T      @──────@      │      │      Y^0.5  │      X^0.5  @──────@      Y^0.5  @──────@      │      Y^0.5  │      │      T      @──────@
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      X^0.5  │      T      │      X^0.5  @──────┼──────┼──────┼──────┼──────@      Y^0.5
  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │
  │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      T      │      │      │      │      │
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
  H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H      H
  │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │      │
```

Look carefully at lines 7-9 of the diagram:

```
  X^0.5  Y^0.5  │      │      │      @──────┼──────┼──────┼──────┼──────@      X^0.5  │      │      │      │      │      X^0.5  X^0.5  │
  │      │      │      │      │      │      │      │      Y^0.5  @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │
  │      │      │      │      │      │      │      @──────┼──────┼──────┼──────┼──────@      │      │      │      │      │      │      │
```

These three lines all have gates; they are not vertically separated by a layer with no gates. This indicates they came from the same moment. But there is no same-moment indicator on the left or right.

Either these lines should not be placed together as they are, or the moment indicator should have been included.




Discussion:
I've been trying to look into this and, for what it's worth, the following code reproduces this issue with a more simple circuit:

```
import cirq
qubits = [cirq.GridQubit(x, y) for x in range(8) for y in range(8)]
c0 = cirq.H(qubits[0])
c7 = cirq.H(qubits[7])
cz14 = cirq.CZ(qubits[1], qubits[4])
cz25 = cirq.CZ(qubits[2], qubits[5])
cz36 = cirq.CZ(qubits[3], qubits[6])
moment1 = cirq.Moment([c0, cz14, cz25, c7])
moment2 = cirq.Moment([c0, cz14, cz25, cz36, c7])
moment3 = cirq.Moment([cz14, cz25, cz36])
moment4 = cirq.Moment([cz25, cz36])
circuit = cirq.Circuit((moment1, moment2, moment3, moment4))
print(circuit)
```
Output:
```
                     ┌───┐  ┌──┐
(0, 0): ───H────H─────────────────

(0, 1): ───@────@─────@───────────
           │    │     │
(0, 2): ───┼@───┼@────┼@─────@────
           ││   ││    ││     │
(0, 3): ───┼┼───┼┼@───┼┼@────┼@───
           ││   │││   │││    ││
(0, 4): ───@┼───@┼┼───@┼┼────┼┼───
            │    ││    ││    ││
(0, 5): ────@────@┼────@┼────@┼───
                  │     │     │
(0, 6): ──────────@─────@─────@───

(0, 7): ───H────H─────────────────
                     └───┘  └──┘
```

Based on the above, it looks like the issue might be missing movement indicators, though I am still trying to better diagnose and resolve the problem here.
This works properly:

```
import cirq
qubits = [cirq.GridQubit(x, y) for x in range(8) for y in range(8)]
cz14 = cirq.CZ(qubits[1], qubits[4])
cz25 = cirq.CZ(qubits[2], qubits[5])
cz36 = cirq.CZ(qubits[3], qubits[6])
moment1 = cirq.Moment([cz14, cz25])
moment2 = cirq.Moment([cz14, cz25, cz36])
moment3 = cirq.Moment([cz14, cz25, cz36])
moment4 = cirq.Moment([cz25, cz36])
circuit = cirq.Circuit((moment1, moment2, moment3, moment4))
print(circuit)
```

```
           ┌──┐   ┌───┐   ┌───┐   ┌──┐
(0, 1): ────@──────@───────@─────────────
            │      │       │
(0, 2): ────┼@─────┼@──────┼@──────@─────
            ││     ││      ││      │
(0, 3): ────┼┼─────┼┼@─────┼┼@─────┼@────
            ││     │││     │││     ││
(0, 4): ────@┼─────@┼┼─────@┼┼─────┼┼────
             │      ││      ││     ││
(0, 5): ─────@──────@┼──────@┼─────@┼────
                     │       │      │
(0, 6): ─────────────@───────@──────@────
           └──┘   └───┘   └───┘   └──┘
```

This also works properly:

```
import cirq
qubits = [cirq.GridQubit(x, y) for x in range(8) for y in range(8)]
c0 = cirq.H(qubits[0])
cz14 = cirq.CZ(qubits[1], qubits[4])
cz25 = cirq.CZ(qubits[2], qubits[5])
cz36 = cirq.CZ(qubits[3], qubits[6])
moment1 = cirq.Moment([c0, cz14, cz25])
moment2 = cirq.Moment([c0, cz14, cz25, cz36])
moment3 = cirq.Moment([cz14, cz25, cz36])
moment4 = cirq.Moment([cz25, cz36])
circuit = cirq.Circuit((moment1, moment2, moment3, moment4))
print(circuit)
```

```
           ┌──┐   ┌───┐   ┌───┐   ┌──┐
(0, 0): ────H──────H─────────────────────

(0, 1): ────@──────@───────@─────────────
            │      │       │
(0, 2): ────┼@─────┼@──────┼@──────@─────
            ││     ││      ││      │
(0, 3): ────┼┼─────┼┼@─────┼┼@─────┼@────
            ││     │││     │││     ││
(0, 4): ────@┼─────@┼┼─────@┼┼─────┼┼────
             │      ││      ││     ││
(0, 5): ─────@──────@┼──────@┼─────@┼────
                     │       │      │
(0, 6): ─────────────@───────@──────@────
           └──┘   └───┘   └───┘   └──┘

```

This, however, doesn't:

```
import cirq
qubits = [cirq.GridQubit(x, y) for x in range(8) for y in range(8)]
c7 = cirq.H(qubits[7])
cz14 = cirq.CZ(qubits[1], qubits[4])
cz25 = cirq.CZ(qubits[2], qubits[5])
cz36 = cirq.CZ(qubits[3], qubits[6])
moment1 = cirq.Moment([cz14, cz25, c7])
moment2 = cirq.Moment([cz14, cz25, cz36, c7])
moment3 = cirq.Moment([cz14, cz25, cz36])
moment4 = cirq.Moment([cz25, cz36])
circuit = cirq.Circuit((moment1, moment2, moment3, moment4))
print(circuit)
```

```
                      ┌───┐   ┌──┐
(0, 1): ───@────@──────@─────────────
           │    │      │
(0, 2): ───┼@───┼@─────┼@──────@─────
           ││   ││     ││      │
(0, 3): ───┼┼───┼┼@────┼┼@─────┼@────
           ││   │││    │││     ││
(0, 4): ───@┼───@┼┼────@┼┼─────┼┼────
            │    ││     ││     ││
(0, 5): ────@────@┼─────@┼─────@┼────
                  │      │      │
(0, 6): ──────────@──────@──────@────

(0, 7): ───H────H────────────────────
                      └───┘   └──┘
```

Perhaps the problem is due to the single gates present at the end of the lines which were supposed to be grouped.
Thanks so much @Ashalynd - I think that you are right! In addition to the single gate at the bottom, it looks like the order within the movement also seems to impact whether this error occurs:

```
import cirq
qubits = [cirq.GridQubit(x, y) for x in range(5) for y in range(5)]
c3 = cirq.H(qubits[3])
cz02 = cirq.CZ(qubits[0], qubits[2])
cz14 = cirq.CZ(qubits[1], qubits[4])
moment1 = cirq.Moment([cz14, c3, cz02])
moment2 = cirq.Moment([cz02, cz14, c3])
moment3 = cirq.Moment([cz02, c3, cz14])
circuit = cirq.Circuit((moment1, moment2, moment3))
print(circuit.to_text_diagram)
print(circuit.to_text_diagram())```
```
```
<bound method Circuit.to_text_diagram of cirq.Circuit(moments=[
    cirq.Moment(operations=[
        cirq.CZ.on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 4)),
        cirq.H.on(cirq.GridQubit(0, 3)),
        cirq.CZ.on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 2)),
    ]),
    cirq.Moment(operations=[
        cirq.CZ.on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 2)),
        cirq.CZ.on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 4)),
        cirq.H.on(cirq.GridQubit(0, 3)),
    ]),
    cirq.Moment(operations=[
        cirq.CZ.on(cirq.GridQubit(0, 0), cirq.GridQubit(0, 2)),
        cirq.H.on(cirq.GridQubit(0, 3)),
        cirq.CZ.on(cirq.GridQubit(0, 1), cirq.GridQubit(0, 4)),
    ]),
])>
          ┌──┐      ┌──┐
(0, 0): ────@───@────@────
            │   │    │
(0, 1): ───@┼───┼@───┼@───
           ││   ││   ││
(0, 2): ───┼@───@┼───@┼───
           │     │    │
(0, 3): ───┼H───H┼───H┼───
           │     │    │
(0, 4): ───@─────@────@───
          └──┘      └──┘
```
I am going to continue looking into this, but thanks so much for your help here!

Resolving patch:
diff --git a/cirq/circuits/circuit.py b/cirq/circuits/circuit.py
--- a/cirq/circuits/circuit.py
+++ b/cirq/circuits/circuit.py
@@ -1652,6 +1652,7 @@ def _draw_moment_in_diagram(
     if not moment.operations:
         out_diagram.write(x0, 0, '')
 
+    max_x = x0
     for op in moment.operations:
         indices = [qubit_map[q] for q in op.qubits]
         y1 = min(indices)
@@ -1689,10 +1690,12 @@ def _draw_moment_in_diagram(
                 # Add an exponent to every label
                 for index in indices:
                     out_diagram.write(x, index, '^' + exponent)
+        if x > max_x:
+            max_x = x
 
     # Group together columns belonging to the same Moment.
-    if moment.operations and x > x0:
-        moment_groups.append((x0, x))
+    if moment.operations and max_x > x0:
+        moment_groups.append((x0, max_x))
 
 
 def _draw_moment_groups_in_diagram(moment_groups: List[Tuple[int, int]],


Test patch:
diff --git a/cirq/circuits/circuit_test.py b/cirq/circuits/circuit_test.py
--- a/cirq/circuits/circuit_test.py
+++ b/cirq/circuits/circuit_test.py
@@ -2851,19 +2851,19 @@ def test_submoments():
     )
 
     cirq.testing.assert_has_diagram(circuit, """
-          ┌───────────┐
-0: ───H────@──────────────@────────
-           │              │
-1: ───@────┼@─────────────┼────────
-      │    ││             │
-2: ───@────┼┼────@────────┼────H───
-           ││    │        │
-3: ───H────@┼────┼────────X^0.5────
+          ┌───────────┐   ┌──────┐
+0: ───H────@───────────────@─────────
+           │               │
+1: ───@────┼@──────────────┼─────────
+      │    ││              │
+2: ───@────┼┼────@─────────┼────H────
+           ││    │         │
+3: ───H────@┼────┼─────────X^0.5─────
             │    │
-4: ─────────X^0.5┼────────H────────
+4: ─────────X^0.5┼─────────H─────────
                  │
-5: ──────────────X^0.5─────────────
-          └───────────┘
+5: ──────────────X^0.5───────────────
+          └───────────┘   └──────┘
 """)
 
     cirq.testing.assert_has_diagram(circuit, """
@@ -2877,25 +2877,27 @@ def test_submoments():
 │ │ │ @─┼─────┼─────X^0.5 │
 └╴│ │ │ │     │     │    ╶┘
   │ │ │ │     │     │
-  @─┼─┼─X^0.5 H     │
-  │ │ H │     │     │
+┌╴│ │ │ │     │     │    ╶┐
+│ @─┼─┼─X^0.5 H     │     │
+│ │ │ H │     │     │     │
+└╴│ │ │ │     │     │    ╶┘
   │ │ │ │     │     │
 """, transpose=True)
 
     cirq.testing.assert_has_diagram(circuit, r"""
-          /-----------\
-0: ---H----@--------------@--------
-           |              |
-1: ---@----|@-------------|--------
-      |    ||             |
-2: ---@----||----@--------|----H---
-           ||    |        |
-3: ---H----@|----|--------X^0.5----
+          /-----------\   /------\
+0: ---H----@---------------@---------
+           |               |
+1: ---@----|@--------------|---------
+      |    ||              |
+2: ---@----||----@---------|----H----
+           ||    |         |
+3: ---H----@|----|---------X^0.5-----
             |    |
-4: ---------X^0.5|--------H--------
+4: ---------X^0.5|---------H---------
                  |
-5: --------------X^0.5-------------
-          \-----------/
+5: --------------X^0.5---------------
+          \-----------/   \------/
 """, use_unicode_characters=False)
 
     cirq.testing.assert_has_diagram(circuit, r"""
@@ -2909,8 +2911,10 @@ def test_submoments():
 | | | @-------------X^0.5 |
 \ | | | |     |     |     /
   | | | |     |     |
-  @-----X^0.5 H     |
-  | | H |     |     |
+/ | | | |     |     |     \
+| @-----X^0.5 H     |     |
+| | | H |     |     |     |
+\ | | | |     |     |     /
   | | | |     |     |
 """, use_unicode_characters=False, transpose=True)
 
@@ -2966,3 +2970,35 @@ def test_pow_valid_only_for_minus_1():
 def test_device_propagates():
     c = cirq.Circuit(device=moment_and_op_type_validating_device)
     assert c[:].device is moment_and_op_type_validating_device
+
+def test_moment_groups():
+    qubits = [cirq.GridQubit(x, y) for x in range(8) for y in range(8)]
+    c0 = cirq.H(qubits[0])
+    c7 = cirq.H(qubits[7])
+    cz14 = cirq.CZ(qubits[1], qubits[4])
+    cz25 = cirq.CZ(qubits[2], qubits[5])
+    cz36 = cirq.CZ(qubits[3], qubits[6])
+    moment1 = cirq.Moment([c0, cz14, cz25, c7])
+    moment2 = cirq.Moment([c0, cz14, cz25, cz36, c7])
+    moment3 = cirq.Moment([cz14, cz25, cz36])
+    moment4 = cirq.Moment([cz25, cz36])
+    circuit = cirq.Circuit((moment1, moment2, moment3, moment4))
+    cirq.testing.assert_has_diagram(circuit, r"""
+           ┌──┐   ┌───┐   ┌───┐   ┌──┐
+(0, 0): ────H──────H─────────────────────
+
+(0, 1): ────@──────@───────@─────────────
+            │      │       │
+(0, 2): ────┼@─────┼@──────┼@──────@─────
+            ││     ││      ││      │
+(0, 3): ────┼┼─────┼┼@─────┼┼@─────┼@────
+            ││     │││     │││     ││
+(0, 4): ────@┼─────@┼┼─────@┼┼─────┼┼────
+             │      ││      ││     ││
+(0, 5): ─────@──────@┼──────@┼─────@┼────
+                     │       │      │
+(0, 6): ─────────────@───────@──────@────
+
+(0, 7): ────H──────H─────────────────────
+           └──┘   └───┘   └───┘   └──┘
+""", use_unicode_characters=True)