Repository: quantumlib/Cirq

Issue:
two_qubit_state_tomography is broken
This code (modified from qubit_characterization_test.py) works:

```python
def test_two_qubit_state_tomography_2():
    simulator = sim.Simulator()
    q_0 = GridQubit(0, 0)
    q_1 = GridQubit(0, 1)
    circuit = circuits.Circuit.from_ops(
        ops.H(q_0), ops.CNOT(q_0, q_1)
    )
    act_rho = two_qubit_state_tomography(simulator, q_0, q_1, circuit,
                                            100000).data
    tar_rho = np.array([1, 0, 0, 1])/np.sqrt(2)
    tar_rho = tar_rho[:, np.newaxis]
    tar_rho = np.dot(tar_rho, tar_rho.T)

    print()
    print(np.round(tar_rho, 3))
    print(np.round(act_rho, 3))

    np.testing.assert_allclose(tar_rho, act_rho, atol=0.1)
```

However, if you change it to 

```python
    circuit = circuits.Circuit.from_ops(
        ops.H(q_0), ops.H(q_1)
    )
    ...
    tar_rho = np.array([1, 1, 1, 1])/2
```

it does not give the correct answer. The density matrix should be

```
[[0.25 0.25 0.25 0.25]
 [0.25 0.25 0.25 0.25]
 [0.25 0.25 0.25 0.25]
 [0.25 0.25 0.25 0.25]]
```

but it's actually

```
[[ 0.083+0.j    -0.042+0.041j  0.042+0.042j  0.001+0.084j]
 [-0.042-0.041j  0.166+0.j     0.165+0.j    -0.043+0.207j]
 [ 0.042-0.042j  0.165-0.j     0.166+0.j     0.042+0.209j]
 [ 0.001-0.084j -0.043-0.207j  0.042-0.209j  0.585+0.j   ]]
```




Discussion:
@XiaoMiQC 

Resolving patch:
diff --git a/cirq/experiments/qubit_characterizations.py b/cirq/experiments/qubit_characterizations.py
--- a/cirq/experiments/qubit_characterizations.py
+++ b/cirq/experiments/qubit_characterizations.py
@@ -358,7 +358,7 @@ def two_qubit_state_tomography(sampler: sim.Sampler,
 
     And if a Y/2 rotation is applied to the first qubit and a X/2 rotation
     is applied to the second qubit before measurement, the measurement
-    operators are (I -/+ sigma_x) \bigotimes (I +/- sigma_y). The probabilites
+    operators are (I -/+ sigma_x) \bigotimes (I +/- sigma_y). The probabilities
     obtained instead contribute to the following linear equations:
 
     c_02 - c_10 - c_12 = 4*P_00 - 1
@@ -428,9 +428,9 @@ def _measurement(two_qubit_circuit: circuits.Circuit) -> np.ndarray:
         for j, rot_2 in enumerate(rots):
             m_idx, indices, signs = _indices_after_basis_rot(i, j)
             mat[m_idx: (m_idx + 3), indices] = s * np.tile(signs, (3, 1))
-            test_circuit = circuit + circuits.Circuit.from_ops(rot_1(
-                second_qubit))
-            test_circuit.append(rot_2(first_qubit))
+            test_circuit = circuit + circuits.Circuit.from_ops(
+                rot_1(first_qubit))
+            test_circuit.append(rot_2(second_qubit))
             probs = np.concatenate((probs, _measurement(test_circuit)))
 
     c, _, _, _ = np.linalg.lstsq(mat, 4.0 * probs - 1.0, rcond=-1)
@@ -451,7 +451,7 @@ def _indices_after_basis_rot(i: int, j: int) -> Tuple[int, Sequence[int],
     q_0_i = 3 - i
     q_1_j = 3 - j
     indices = [q_1_j - 1, 4 * q_0_i - 1, 4 * q_0_i + q_1_j - 1]
-    signs = [(-1) ** (j == 2), (-1) ** (i == 2), (-1) ** (i == 2 + j == 2)]
+    signs = [(-1)**(j == 2), (-1)**(i == 2), (-1)**((i == 2) + (j == 2))]
     return mat_idx, indices, signs
 
 


Test patch:
diff --git a/cirq/experiments/qubit_characterizations_test.py b/cirq/experiments/qubit_characterizations_test.py
--- a/cirq/experiments/qubit_characterizations_test.py
+++ b/cirq/experiments/qubit_characterizations_test.py
@@ -76,7 +76,10 @@ def test_single_qubit_state_tomography():
 
 def test_two_qubit_state_tomography():
     # Check that the density matrices of the four Bell states closely match
-    # the ideal cases.
+    # the ideal cases. In addition, check that the output states of
+    # single-qubit rotations (H, H), (X/2, Y/2), (Y/2, X/2) have the correct
+    # density matrices.
+
     simulator = sim.Simulator()
     q_0 = GridQubit(0, 0)
     q_1 = GridQubit(0, 1)
@@ -88,6 +91,9 @@ def test_two_qubit_state_tomography():
                                            ops.CNOT(q_0, q_1))
     circuit_11 = circuits.Circuit.from_ops(ops.X(q_0), ops.X(q_1), ops.H(q_0),
                                            ops.CNOT(q_0, q_1))
+    circuit_hh = circuits.Circuit.from_ops(ops.H(q_0), ops.H(q_1))
+    circuit_xy = circuits.Circuit.from_ops(ops.X(q_0)**0.5, ops.Y(q_1)**0.5)
+    circuit_yx = circuits.Circuit.from_ops(ops.Y(q_0)**0.5, ops.X(q_1)**0.5)
 
     act_rho_00 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_00,
                                             100000).data
@@ -97,13 +103,25 @@ def test_two_qubit_state_tomography():
                                             100000).data
     act_rho_11 = two_qubit_state_tomography(simulator, q_0, q_1, circuit_11,
                                             100000).data
+    act_rho_hh = two_qubit_state_tomography(simulator, q_0, q_1, circuit_hh,
+                                            100000).data
+    act_rho_xy = two_qubit_state_tomography(simulator, q_0, q_1, circuit_xy,
+                                            100000).data
+    act_rho_yx = two_qubit_state_tomography(simulator, q_0, q_1, circuit_yx,
+                                            100000).data
 
     tar_rho_00 = np.outer([1.0, 0, 0, 1.0], [1.0, 0, 0, 1.0]) / 2.0
     tar_rho_01 = np.outer([0, 1.0, 1.0, 0], [0, 1.0, 1.0, 0]) / 2.0
     tar_rho_10 = np.outer([1.0, 0, 0, -1.0], [1.0, 0, 0, -1.0]) / 2.0
     tar_rho_11 = np.outer([0, 1.0, -1.0, 0], [0, 1.0, -1.0, 0]) / 2.0
+    tar_rho_hh = np.outer([0.5, 0.5, 0.5, 0.5], [0.5, 0.5, 0.5, 0.5])
+    tar_rho_xy = np.outer([0.5, 0.5, -0.5j, -0.5j], [0.5, 0.5, 0.5j, 0.5j])
+    tar_rho_yx = np.outer([0.5, -0.5j, 0.5, -0.5j], [0.5, 0.5j, 0.5, 0.5j])
 
     np.testing.assert_almost_equal(act_rho_00, tar_rho_00, decimal=1)
     np.testing.assert_almost_equal(act_rho_01, tar_rho_01, decimal=1)
     np.testing.assert_almost_equal(act_rho_10, tar_rho_10, decimal=1)
     np.testing.assert_almost_equal(act_rho_11, tar_rho_11, decimal=1)
+    np.testing.assert_almost_equal(act_rho_hh, tar_rho_hh, decimal=1)
+    np.testing.assert_almost_equal(act_rho_xy, tar_rho_xy, decimal=1)
+    np.testing.assert_almost_equal(act_rho_yx, tar_rho_yx, decimal=1)