Ion Device Class

The IonDevice represents a trapped ion quantum computer with all-to-all qubit connectivity. The number of qubits as well as the duration of gates and measurements are specified by the user when creating an ion device.

Two-qubit gates are implemented by an Ising-type coupling known as the Mølmer–Sørensen gate. The Mølmer–Sørensen gate couples ions through the shared motional modes of the ion chain. The ion motion and internal state decouples at the end of each gate. The IonDevice class assumes this decoupling is perfect and does not explicitly model the ion motion.

try:
import cirq
except ImportError:
print("installing cirq...")
!pip install cirq --quiet
print("installed cirq.")
import cirq

import numpy as np


Defining an IonDevice

To define an IonDevice, we specify

• The set of qubits in the device,
• The duration of single-qubit gates,
• The duration of two-qubit gates, and
• The duration of measurement gates.

The code below creates an IonDevice with four qubits in a linear array. The durations we use for each type of gate are reasonable order-of-magnitude estimates, though they will differ for different trapped ion computers.

"""Create an IonDevice."""
ion_device = cirq.IonDevice(
qubits=cirq.LineQubit.range(4),
oneq_gates_duration=cirq.Duration(micros=10),
twoq_gates_duration=cirq.Duration(micros=200),
measurement_duration=cirq.Duration(micros=100)
)


We can view some properties of the ion_device as shown below.

"""View some properties of the device."""
# Display the ion device.
print("Ion Device:\n", ion_device)

# Get all qubits in the device.
print("\nQubits in the IonDevice:\n", sorted(ion_device.qubits))

# Get a qubit at a certain position (if present).
pos = 2
print(f"\nQubit at position {pos}:\n", ion_device.at(pos))

Ion Device:
0───1───2───3

Qubits in the IonDevice:
[cirq.LineQubit(0), cirq.LineQubit(1), cirq.LineQubit(2), cirq.LineQubit(3)]

Qubit at position 2:
2


Native Gate Set

An IonDevice can implement single-qubit rotations about the $$X$$, $$Y$$, and $$Z$$ axes of the Bloch sphere: namely, cirq.rx, cirq.ry, and cirq.rz.

An IonDevice can implement the two-qubit Mølmer–Sørensen gate, a rotation about the $$XX$$ axis in the two-qubit Bloch sphere defined as

$$\exp(-i t XX) = \left[ \begin{matrix} \cos t & 0 & 0 & -i \sin t \ 0 & \cos t & -i \sin t & 0 \ 0 & -i \sin t & \cos t & 0 \ -i \sin t & 0 & 0 & \cos t \end{matrix} \right] .$$

The Mølmer–Sørensen gate is defined in Cirq as cirq.ms.

One can check if a given gate is valid with IonDevice.validate_gate. This method raises an error if the gate is invalid (not supported by the device) and does nothing if the gate is valid (supported by the device).

"""Check if gates are valid. Invalid gates raise a ValueError."""
# Single-qubit X rotation of any angle is supported.
ion_device.validate_gate(cirq.rx(np.pi / 7))

# Single-qubit Z rotation of any angle is supported.
ion_device.validate_gate(cirq.rz(np.pi / 5))

# Mølmer–Sørensen gate of any angle is supported.
ion_device.validate_gate(cirq.ms(np.pi / 4))


One can also validate operations and circuits with IonDevice.validate_operation and IonDevice.validate_circuit, respectively.

We can get the duration of valid operations as follows.

"""Get the duration of valid operations."""
# Duration of a single-qubit operation.
ion_device.duration_of(cirq.ry(np.pi / 2).on(ion_device.at(0)))

cirq.Duration(micros=10)


Decomposing Operations and Circuits

Operations which are not valid on the device can be decomposed into a set of valid operations. For example, a CNOT gate is not supported but can be implemented with the following decomposition.

"""Decompose a CNOT operation into valid IonDevice operations."""
# Get a CNOT operation.
op = cirq.CNOT(ion_device.at(0), ion_device.at(1))

# Decompose it for the IonDevice.
ion_device_ops = cirq.ConvertToIonGates().convert_one(op)

# Print the sequence of operations to implement a CNOT.
print("Sequence of IonDevice operations for a CNOT:\n")
print(cirq.Circuit(ion_device_ops))

Sequence of IonDevice operations for a CNOT:

0: ───Ry(0.5π)───MS(0.25π)───Rx(-0.5π)───Ry(-0.5π)───
│
1: ──────────────MS(0.25π)───Rx(-0.5π)───────────────


Circuits can also be decomposed in a similar manner using IonDevice.decompose_circuit.

"""Decompose a circuit into IonDevice operations."""
# Example circuit to decompose.
circuit = cirq.Circuit(
cirq.H(cirq.LineQubit(0)),
cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(1)),
cirq.CNOT(cirq.LineQubit(0), cirq.LineQubit(2))
)

# Display it.
print("Circuit to decompose:\n")
print(circuit)

# Decompose the circuit.
ion_device_circuit = ion_device.decompose_circuit(circuit)

# Display the decomposed circuit.
print("\nIonDevice circuit:\n")
print(ion_device_circuit)

Circuit to decompose:

0: ───H───@───@───
│   │
1: ───────X───┼───
│
2: ───────────X───

IonDevice circuit:

0: ───PhX(1)───────────MS(0.25π)───PhX(1)^0.5───────────MS(0.25π)───PhX(-0.5)^0.5───S^-1───
│                                │
1: ────────────────────MS(0.25π)───PhX(1)^0.5───────────┼──────────────────────────────────
│
2: ─────────────────────────────────────────────────────MS(0.25π)───PhX(1)^0.5─────────────

[{ "type": "thumb-down", "id": "missingTheInformationINeed", "label":"Missing the information I need" },{ "type": "thumb-down", "id": "tooComplicatedTooManySteps", "label":"Too complicated / too many steps" },{ "type": "thumb-down", "id": "outOfDate", "label":"Out of date" },{ "type": "thumb-down", "id": "samplesCodeIssue", "label":"Samples / code issue" },{ "type": "thumb-down", "id": "otherDown", "label":"Other" }]
[{ "type": "thumb-up", "id": "easyToUnderstand", "label":"Easy to understand" },{ "type": "thumb-up", "id": "solvedMyProblem", "label":"Solved my problem" },{ "type": "thumb-up", "id": "otherUp", "label":"Other" }]