Repository: quantumlib/Cirq

Issue:
MergeInteractions optimization is creating bad circuits
Not sure how this made it past the tests yet.

```python
def main():
    circuit = make_inefficient_circuit()
    print("BEFORE:")
    print(circuit.to_unitary_matrix().round(3))
    print()
    cirq.google.MergeInteractions().optimize_circuit(circuit)
    print("AFTER:")
    print(circuit.to_unitary_matrix().round(3))

def make_inefficient_circuit(t=0.1, v=0.11):
    from cirq import H, CNOT, Z
    a = cirq.NamedQubit('a')
    b = cirq.NamedQubit('b')

    return cirq.Circuit.from_ops(
        H(b),
        CNOT(a, b),
        H(b),
        CNOT(a, b),
        CNOT(b, a),
        H(a),
        CNOT(a, b),
        Z(a)**t, Z(b)**-t,
        CNOT(a, b),
        H(a), Z(b)**v,
        CNOT(a, b),
        Z(a)**-v, Z(b)**-v)
```

```
BEFORE:
[[ 1.   -0.j     0.   -0.j     0.   +0.j     0.   -0.j   ]
 [-0.   -0.j    -0.   -0.309j  0.951-0.j    -0.   +0.j   ]
 [ 0.   -0.j     0.951-0.j    -0.   -0.309j  0.   +0.j   ]
 [-0.   +0.j     0.   +0.j     0.   -0.j    -0.771+0.637j]]

AFTER:
[[-0.354-0.354j -0.354-0.354j -0.227-0.446j  0.227+0.446j]
 [-0.452-0.213j -0.452-0.213j  0.364+0.342j -0.364-0.342j]
 [-0.354-0.354j  0.354+0.354j -0.446-0.227j -0.446-0.227j]
 [-0.452-0.213j  0.452+0.213j  0.496+0.063j  0.496+0.063j]]
```


Discussion:

Resolving patch:
diff --git a/cirq/google/merge_interactions.py b/cirq/google/merge_interactions.py
--- a/cirq/google/merge_interactions.py
+++ b/cirq/google/merge_interactions.py
@@ -95,9 +95,9 @@ def _op_to_matrix(self,
         if op.qubits == (q2, q1):
             return MergeInteractions._flip_kron_order(m), True
         if op.qubits == (q1,):
-            return np.kron(np.eye(2), m), False
-        if op.qubits == (q2,):
             return np.kron(m, np.eye(2)), False
+        if op.qubits == (q2,):
+            return np.kron(np.eye(2), m), False
 
         return None
 


Test patch:
diff --git a/cirq/google/merge_interactions_test.py b/cirq/google/merge_interactions_test.py
--- a/cirq/google/merge_interactions_test.py
+++ b/cirq/google/merge_interactions_test.py
@@ -12,6 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+from cirq import testing
 from cirq import circuits
 from cirq import ops
 from cirq.google import ExpZGate, MergeInteractions, MergeRotations
@@ -39,6 +40,16 @@ def assert_optimizes(before, after):
         print(after)
     assert before == after
 
+def assert_optimization_not_broken(circuit):
+    """Check that the unitary matrix for the input circuit is the same (up to
+    global phase and rounding error) as the unitary matrix of the optimized
+    circuit."""
+    u_before = circuit.to_unitary_matrix()
+    MergeInteractions().optimize_circuit(circuit)
+    u_after = circuit.to_unitary_matrix()
+
+    testing.assert_allclose_up_to_global_phase(u_before, u_after, atol=1e-8)
+
 
 def test_clears_paired_cnot():
     q0 = ops.QubitId()
@@ -84,3 +95,49 @@ def test_ignores_czs_separated_by_outer_cz():
             circuits.Moment([ops.CZ(q00, q10)]),
             circuits.Moment([ops.CZ(q00, q01)]),
         ]))
+
+
+def test_cnots_separated_by_single_gates_correct():
+    q0 = ops.QubitId()
+    q1 = ops.QubitId()
+    assert_optimization_not_broken(
+        circuits.Circuit.from_ops(
+            ops.CNOT(q0, q1),
+            ops.H(q1),
+            ops.CNOT(q0, q1),
+        ))
+
+
+def test_czs_separated_by_single_gates_correct():
+    q0 = ops.QubitId()
+    q1 = ops.QubitId()
+    assert_optimization_not_broken(
+        circuits.Circuit.from_ops(
+            ops.CZ(q0, q1),
+            ops.X(q1),
+            ops.X(q1),
+            ops.X(q1),
+            ops.CZ(q0, q1),
+        ))
+
+
+def test_inefficient_circuit_correct():
+    t = 0.1
+    v = 0.11
+    q0 = ops.QubitId()
+    q1 = ops.QubitId()
+    assert_optimization_not_broken(
+        circuits.Circuit.from_ops(
+            ops.H(q1),
+            ops.CNOT(q0, q1),
+            ops.H(q1),
+            ops.CNOT(q0, q1),
+            ops.CNOT(q1, q0),
+            ops.H(q0),
+            ops.CNOT(q0, q1),
+            ops.Z(q0)**t, ops.Z(q1)**-t,
+            ops.CNOT(q0, q1),
+            ops.H(q0), ops.Z(q1)**v,
+            ops.CNOT(q0, q1),
+            ops.Z(q0)**-v, ops.Z(q1)**-v,
+        ))