Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
105 changes: 73 additions & 32 deletions cirq/experiments/qubit_characterizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,39 @@
# See the License for the specific language governing permissions and
# limitations under the License.

import dataclasses
import itertools

from typing import Any, Iterator, List, NamedTuple, Optional, Sequence, Tuple
from typing import Any, Iterator, List, Optional, Sequence, Tuple
import numpy as np
import sympy

from matplotlib import pyplot as plt
from mpl_toolkits.mplot3d import Axes3D # type: ignore # pylint: disable=unused-import
from cirq import circuits, devices, ops, protocols, study, work

Cliffords = NamedTuple('Cliffords', [('c1_in_xy', List[List[ops.Gate]]),
('c1_in_xz', List[List[ops.Gate]]),
('s1', List[List[ops.Gate]]),
('s1_x', List[List[ops.Gate]]),
('s1_y', List[List[ops.Gate]])])

@dataclasses.dataclass
class Cliffords:
"""The single-qubit Clifford group, decomposed into elementary gates.

The decomposition of the Cliffords follows those described in
Barends et al., Nature 508, 500 (https://arxiv.org/abs/1402.4848).

Decompositions of the Clifford group:
c1_in_xy: decomposed into XPowGate and YPowGate.
c1_in_xz: decomposed into XPowGate and ZPowGate, with at most one
XPowGate (one microwave gate) per Clifford.

Subsets used to generate the 2-qubit Clifford group (see paper table S7):
s1
s1_x
s1_y
"""
c1_in_xy: List[List[ops.Gate]]
c1_in_xz: List[List[ops.Gate]]
s1: List[List[ops.Gate]]
s1_x: List[List[ops.Gate]]
s1_y: List[List[ops.Gate]]


class RabiResult:
Expand Down Expand Up @@ -647,7 +665,7 @@ def _two_qubit_clifford(q_0: devices.GridQubit, q_1: devices.GridQubit,
An integer (idx) from 0 to 11519 is used to generate a two-qubit Clifford
gate which is constructed with single-qubit X and Y rotations and CZ gates.
The decomposition of the Cliffords follow those described in the appendix
of Barends et al., Nature 508, 500.
of Barends et al., Nature 508, 500 (https://arxiv.org/abs/1402.4848).

The integer idx is first decomposed into idx_0 (which ranges from 0 to
23), idx_1 (ranging from 0 to 23) and idx_2 (ranging from 0 to 19). idx_0
Expand Down Expand Up @@ -744,33 +762,56 @@ def _single_qubit_gates(gate_seq: Sequence[ops.Gate],


def _single_qubit_cliffords() -> Cliffords:
X, Y, Z = ops.X, ops.Y, ops.Z

c1_in_xy = [] # type: List[List[ops.Gate]]
c1_in_xz = [] # type: List[List[ops.Gate]]

for phi_0, phi_1 in itertools.product([1.0, 0.5, -0.5], [0.0, 0.5, -0.5]):
c1_in_xy.append([ops.X**phi_0, ops.Y**phi_1])
c1_in_xy.append([ops.Y**phi_0, ops.X**phi_1])
c1_in_xz.append([ops.X**phi_0, ops.Z**phi_1])
c1_in_xz.append([ops.Z**phi_0, ops.X**phi_1])

c1_in_xy.append([ops.X**0.0])
c1_in_xy.append([ops.Y, ops.X])

phi_xy = [[-0.5, 0.5, 0.5], [-0.5, -0.5, 0.5], [0.5, 0.5, 0.5],
[-0.5, 0.5, -0.5]]
for phi in phi_xy:
c1_in_xy.append([ops.X**phi[0], ops.Y**phi[1], ops.X**phi[2]])

phi_xz = [[0.5, 0.5, -0.5], [0.5, -0.5, -0.5], [-0.5, -0.5, -0.5],
[-0.5, 0.5, -0.5]]
for phi in phi_xz:
c1_in_xz.append([ops.X**phi[0], ops.Z**phi[1], ops.X**phi[2]])

s1 = [[ops.X**0.0], [ops.Y**0.5, ops.X**0.5],
[ops.X**-0.5, ops.Y**-0.5]] # type: List[List[ops.Gate]]
s1_x = [[ops.X**0.5], [ops.X**0.5, ops.Y**0.5, ops.X**0.5],
[ops.Y**-0.5]] # type: List[List[ops.Gate]]
s1_y = [[ops.Y**0.5], [ops.X**-0.5, ops.Y**-0.5, ops.X**0.5],
[ops.Y, ops.X**0.5]] # type: List[List[ops.Gate]]
c1_in_xy.append([X**phi_0, Y**phi_1])
c1_in_xy.append([Y**phi_0, X**phi_1])
c1_in_xz.append([X**phi_0, Z**phi_1])
c1_in_xz.append([Z**phi_0, X**phi_1])

# identity
c1_in_xy.append([X**0.0])
c1_in_xz.append([X**0.0])

c1_in_xy.append([Y, X])
c1_in_xz.append([Z, X])

phi_xy = [
[-0.5, 0.5, 0.5],
[-0.5, -0.5, 0.5],
[0.5, 0.5, 0.5],
[-0.5, 0.5, -0.5],
]
for y0, x, y1 in phi_xy:
c1_in_xy.append([Y**y0, X**x, Y**y1])

phi_xz = [
[0.5, 0.5, -0.5],
[0.5, -0.5, -0.5],
[-0.5, -0.5, -0.5],
[-0.5, 0.5, -0.5],
]
for z0, x, z1 in phi_xz:
c1_in_xz.append([Z**z0, X**x, Z**z1])

s1 = [
[X**0.0],
[Y**0.5, X**0.5],
[X**-0.5, Y**-0.5],
] # type: List[List[ops.Gate]]
s1_x = [
[X**0.5],
[X**0.5, Y**0.5, X**0.5],
[Y**-0.5],
] # type: List[List[ops.Gate]]
s1_y = [
[Y**0.5],
[X**-0.5, Y**-0.5, X**0.5],
[Y, X**0.5],
] # type: List[List[ops.Gate]]
Copy link
Collaborator

@viathor viathor Oct 14, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Maybe add comments up where Cliffords named tuple type is defined explaining the meaning of the five fields.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed Cliffords to a dataclass and added some documentation about what these are.


return Cliffords(c1_in_xy, c1_in_xz, s1, s1_x, s1_y)
40 changes: 40 additions & 0 deletions cirq/experiments/qubit_characterizations_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

import matplotlib.pyplot as plt

import cirq
import cirq.experiments.qubit_characterizations as ceqc
from cirq import GridQubit
from cirq import circuits, ops, sim
from cirq.experiments import (rabi_oscillations,
Expand All @@ -40,6 +42,44 @@ def test_rabi_oscillations():
assert rms_err < 0.1


def test_single_qubit_cliffords():
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Optional: It seems easy to write a unit test that verifies the key property of the Clifford group - that it fixes the Pauli group - but it seems we don't have it. WDYT about adding it?

(Strictly speaking this isn't related to this PR, but if we had this test then observing it pass before and after would provide a lot of confidence in the new logic.)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should have some better abstractions around the pauli group and clifford group, but I think I'll leave that as future work because we'll probably need some design discussion around that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since one of your goals was to ensure at most one microwave gate in each decomposition, could you add a test for this? Otherwise, this can change on you later unexpectedly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea. Done.

cliffords = ceqc._single_qubit_cliffords()
assert len(cliffords.c1_in_xy) == 24
assert len(cliffords.c1_in_xz) == 24

def unitary(gates):
U = np.eye(2)
for gate in gates:
U = cirq.unitary(gate) @ U
return U

xy_unitaries = [unitary(gates) for gates in cliffords.c1_in_xy]
xz_unitaries = [unitary(gates) for gates in cliffords.c1_in_xz]

def check_distinct(unitaries):
n = len(unitaries)
for i in range(n):
for j in range(i + 1, n):
Ui, Uj = unitaries[i], unitaries[j]
assert not cirq.allclose_up_to_global_phase(Ui, Uj), f'{i}, {j}'

# Check that unitaries in each decomposition are distinct.
check_distinct(xy_unitaries)
check_distinct(xz_unitaries)

# Check that each decomposition gives the same set of unitaries.
for Uxy in xy_unitaries:
assert any(
cirq.allclose_up_to_global_phase(Uxy, Uxz) for Uxz in xz_unitaries)

# Check that XZ decomposition has at most one X gate per clifford.
for gates in cliffords.c1_in_xz:
num_x = len([gate for gate in gates if isinstance(gate, cirq.XPowGate)])
num_z = len([gate for gate in gates if isinstance(gate, cirq.ZPowGate)])
assert num_x + num_z == len(gates)
assert num_x <= 1


def test_single_qubit_randomized_benchmarking():
# Check that the ground state population at the end of the Clifford
# sequences is always unity.
Expand Down