Quantum Devices¶
The module parityos.devices offers classes to define the structure, capabilities, and constraints of a quantum device, enabling high-level simulations and hardware-aware circuit compilation.The module provides a high-level abstraction of a quantum processor. It allows developers to define:
The Physical Layout: The set of qubits and their connectivity.
The Gate Set: The available native operations (gates) and their parameters.
The Error Profile: (Via properties) The noise and characteristics associated with specific qubits or gates.
Core Components¶
Device Qubits¶
The DeviceQubit class represents an individual physical qubit within the quantum processor. It encapsulates a Qubit together with additional metadata or physical properties.
Device Gates¶
The DeviceGate class represents a native operation available on the hardware. It encapsulates an Operator together with additional metadata or physical properties.
Device Models¶
The DeviceModel is the primary container that aggregates device_qubits and device_gates into a cohesive hardware description, giving access to derived properties like e.g. qubit connectivity and gate types derived from the device gates.
Hardware Properties¶
The metadata in DeviceQubit.properties and DeviceGate.properties can be of any type, but ParityOS supplies basic classes BasicQubitProperties and BasicGateProperties as reference implementations.
Automated Device Construction¶
For rapid prototyping, the module provides the utility function uniform_noiseless_device_from_connectivity, which allows to generate a noiseless DeviceModel from a simple DeviceConnectivity of qubit Connections and a set of operator types to create on the device. The function assumes perfect qubits and gates (i.e. gates and qubits with no hardware properties) and a homogeneous device in the sense that every gate type exists on every qubit Connection that supports it.
Example¶
from parityos.bits import get_q
from parityos.devices.device_connectivity import DeviceConnectivity
from parityos.devices.device_model import (
DeviceGate,
DeviceModel,
DeviceQubit,
uniform_noiseless_device_from_connectivity,
)
from parityos.devices.hardware_properties import BasicGateProperties, BasicQubitProperties
from parityos.operators.controlled_operator import CX
from parityos.operators.rotation_operator import RX, RZ
# Device qubit indices vs. location
# 2 -- 3
# | |
# 0 -- 1
qubits = [
get_q(point)
for point in [
(0, 0),
(0, 1),
(1, 0),
(1, 1),
]
]
edges = [
(qubits[0], qubits[1]),
(qubits[0], qubits[2]),
(qubits[1], qubits[3]),
(qubits[2], qubits[3]),
]
connectivity = DeviceConnectivity(edges)
# INHOMOGENEOUS NOISY DEVICE
# with different hardware properties of each qubit and gate and not RX and RZ not on all qubits
device_qubits = [
DeviceQubit(qubits[0], BasicQubitProperties(2.0, 4.1)),
DeviceQubit(qubits[1], BasicQubitProperties(1.2, 2.3)),
DeviceQubit(qubits[2], BasicQubitProperties(2.2, 3.7)),
DeviceQubit(qubits[3], BasicQubitProperties(1.7, 3.9)),
]
single_qubit_device_gates = [
DeviceGate(RZ(qubits[0]), BasicGateProperties(2.1e-4)),
DeviceGate(RX(qubits[1]), BasicGateProperties(5e-5)),
DeviceGate(RZ(qubits[2]), BasicGateProperties(3.2e-4)),
DeviceGate(RX(qubits[3]), BasicGateProperties(2.2e-4)),
]
two_qubit_device_gates = [
DeviceGate(CX(qubits[0], qubits[1]), BasicGateProperties(1e-3)),
DeviceGate(CX(qubits[1], qubits[0]), BasicGateProperties(1e-3)),
DeviceGate(CX(qubits[0], qubits[2]), BasicGateProperties(1.2e-3)),
DeviceGate(CX(qubits[2], qubits[0]), BasicGateProperties(1.2e-3)),
DeviceGate(CX(qubits[1], qubits[3]), BasicGateProperties(2.4e-3)),
DeviceGate(CX(qubits[3], qubits[1]), BasicGateProperties(2.4e-3)),
DeviceGate(CX(qubits[2], qubits[3]), BasicGateProperties(9e-4)),
DeviceGate(CX(qubits[3], qubits[2]), BasicGateProperties(9e-4)),
]
device_gates = single_qubit_device_gates + two_qubit_device_gates
noisy_device = DeviceModel(device_qubits, device_gates)
assert noisy_device.native_operator_types == {RZ, RX, CX}
assert noisy_device.qubits == set(qubits)
assert noisy_device.operators_with_n_qubits(1) == set(single_qubit_device_gates)
assert noisy_device.operators_with_n_qubits(2) == set(two_qubit_device_gates)
# no three-qubit operators
assert not noisy_device.operators_with_n_qubits(3)
# connectivity is derived from device_qubits
assert noisy_device.connectivity == connectivity
# HOMOGENEOUS NOISELESS DEVICE
# no hardware properties and all gates defined on all qubits/edges
noiseless_device = uniform_noiseless_device_from_connectivity(connectivity, [RX, RZ, CX])
assert noiseless_device.native_operator_types == {RZ, RX, CX}
assert noiseless_device.qubits == set(qubits)
assert noiseless_device.connectivity == connectivity
# noiseless device
assert all([device_qubit.properties is None for device_qubit in noiseless_device.device_qubits])
assert all([device_gate.properties is None for device_gate in noiseless_device.device_gates])
# noiseless RX and RZ on every qubit
assert noiseless_device.operators_with_n_qubits(1) == {
DeviceGate(RX(qubit)) for qubit in qubits
} | {DeviceGate(RZ(qubit)) for qubit in qubits}
# noiseless CX in both directions on every edge
assert noiseless_device.operators_with_n_qubits(2) == {
gate
for qubit1, qubit2 in edges
for gate in [DeviceGate(CX(qubit1, qubit2)), DeviceGate(CX(qubit2, qubit1))]
}