A framework for creating, editing, and invoking Noisy Intermediate Scale Quantum (NISQ) circuits.
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
The devices module provides classes for modeling quantum hardware, qubits with different topologies, and realistic noise models for NISQ devices. This enables accurate simulation of quantum computations under realistic conditions.
Abstract base class for all quantum identifiers.
class Qid:
"""Abstract base class for quantum identifiers."""
@property
@abc.abstractmethod
def dimension(self) -> int:
"""Dimension of the quantum system (2 for qubits, >2 for qudits)."""
def _comparison_key(self) -> Any:
"""Key used for comparison and hashing."""
def __lt__(self, other: 'Qid') -> bool:
"""Less than comparison for sorting."""
def validate_dimension(self, dimension: int) -> int:
"""Validate that this qid supports the given dimension."""Qubits arranged in a 2D grid topology, commonly used for superconducting quantum processors.
class GridQubit(Qid):
"""2D grid-based qubit (dimension 2)."""
def __init__(self, row: int, col: int) -> None:
"""Initialize a grid qubit at (row, col)."""
@property
def row(self) -> int:
"""Row coordinate of the qubit."""
@property
def col(self) -> int:
"""Column coordinate of the qubit."""
@property
def dimension(self) -> int:
"""Always returns 2 for qubits."""
@classmethod
def rect(cls, rows: int, cols: int) -> List['GridQubit']:
"""Create a rectangular array of grid qubits."""
@classmethod
def square(cls, length: int) -> List['GridQubit']:
"""Create a square array of grid qubits."""
def neighbors(self, *, diagonal: bool = True) -> Set['GridQubit']:
"""Get neighboring grid positions."""
def is_adjacent(self, other: 'GridQubit') -> bool:
"""Check if this qubit is adjacent to another."""
def __add__(self, other: Tuple[int, int]) -> 'GridQubit':
"""Add a (row, col) offset to this qubit."""
def __sub__(self, other: Tuple[int, int]) -> 'GridQubit':
"""Subtract a (row, col) offset from this qubit."""Generalized version of GridQubit supporting arbitrary dimensions.
class GridQid(Qid):
"""Grid-based qubit identifier (generalized dimension)."""
def __init__(self, row: int, col: int, dimension: int) -> None:
"""Initialize a grid qid with specified dimension."""
@property
def row(self) -> int:
"""Row coordinate."""
@property
def col(self) -> int:
"""Column coordinate."""
@property
def dimension(self) -> int:
"""Dimension of the quantum system."""
def neighbors(self, *, diagonal: bool = True) -> Set['GridQid']:
"""Get neighboring grid positions with same dimension."""Qubits arranged in a linear topology.
class LineQubit(Qid):
"""1D line-based qubit (dimension 2)."""
def __init__(self, x: int) -> None:
"""Initialize a line qubit at position x."""
@property
def x(self) -> int:
"""Position along the line."""
@property
def dimension(self) -> int:
"""Always returns 2 for qubits."""
@classmethod
def range(cls, *args) -> List['LineQubit']:
"""Create a range of line qubits.
Args:
*args: Either range(stop) or range(start, stop) or range(start, stop, step)
"""
def neighbors(self, radius: int = 1) -> Set['LineQubit']:
"""Get neighboring positions within given radius."""
def is_adjacent(self, other: 'LineQubit') -> bool:
"""Check if this qubit is adjacent to another."""Generalized version of LineQubit supporting arbitrary dimensions.
class LineQid(Qid):
"""Line-based qubit identifier (generalized dimension)."""
def __init__(self, x: int, dimension: int) -> None:
"""Initialize a line qid with specified dimension."""
@property
def x(self) -> int:
"""Position along the line."""
@property
def dimension(self) -> int:
"""Dimension of the quantum system."""Base class for modeling quantum devices with hardware constraints.
class Device:
"""Abstract base class for quantum devices."""
@abc.abstractmethod
def qubits(self) -> FrozenSet[Qid]:
"""Qubits available on this device."""
def qubit_set(self) -> FrozenSet[Qid]:
"""Alias for qubits()."""
def decompose_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE':
"""Decompose an operation into device-native operations."""
def validate_operation(self, operation: 'cirq.Operation') -> None:
"""Validate that an operation can be performed on this device."""
def validate_circuit(self, circuit: 'cirq.AbstractCircuit') -> None:
"""Validate that a circuit can be run on this device."""
def validate_moment(self, moment: 'cirq.Moment') -> None:
"""Validate that a moment can be performed on this device."""
def can_add_operation_into_moment(self, operation: 'cirq.Operation', moment: 'cirq.Moment') -> bool:
"""Check if an operation can be added to a moment."""
def duration_of(self, operation: 'cirq.Operation') -> 'cirq.Duration':
"""Get the duration of an operation on this device."""Metadata describing device capabilities and constraints.
class DeviceMetadata:
"""Metadata describing device capabilities."""
def __init__(self, qubits: Iterable[Qid],
pairs: Iterable[Tuple[Qid, Qid]]) -> None:
"""Initialize device metadata."""
@property
def qubits(self) -> FrozenSet[Qid]:
"""Set of qubits on the device."""
@property
def qubit_pairs(self) -> FrozenSet[Tuple[Qid, Qid]]:
"""Set of two-qubit gate pairs."""
def neighbors_of(self, qubit: Qid) -> Set[Qid]:
"""Get neighboring qubits that can interact with the given qubit."""
def isolated_qubits(self) -> FrozenSet[Qid]:
"""Qubits that cannot interact with any other qubits."""Specialized metadata for grid-based quantum devices.
class GridDeviceMetadata(DeviceMetadata):
"""Metadata for grid-based quantum devices."""
def __init__(self, qubit_pairs: Iterable[Tuple[GridQubit, GridQubit]],
gateset: Optional['cirq.Gateset'] = None) -> None:
"""Initialize grid device metadata."""
@classmethod
def square(cls, length: int, **kwargs) -> 'GridDeviceMetadata':
"""Create metadata for a square grid device."""
@classmethod
def rect(cls, rows: int, cols: int, **kwargs) -> 'GridDeviceMetadata':
"""Create metadata for a rectangular grid device."""A device with no constraints that accepts any operation.
UNCONSTRAINED_DEVICE: Device
"""Device with no constraints - accepts any quantum operation."""Base class for modeling quantum noise.
class NoiseModel:
"""Abstract base class for noise models."""
@abc.abstractmethod
def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE':
"""Apply noise to an operation, returning noisy operations."""
def noisy_moment(self, moment: 'cirq.Moment', system_qubits: Sequence[Qid]) -> 'cirq.OP_TREE':
"""Apply noise to all operations in a moment."""
def noisy_moments(self, moments: Sequence['cirq.Moment'], system_qubits: Sequence[Qid]) -> Sequence['cirq.OP_TREE']:
"""Apply noise to a sequence of moments."""
def is_virtual_moment(self, moment: 'cirq.Moment') -> bool:
"""Check if a moment should be treated as virtual (no duration)."""Noise model with constant per-qubit noise rates.
class ConstantQubitNoiseModel(NoiseModel):
"""Noise model with constant per-qubit noise."""
def __init__(self, qubit_noise_gate: 'cirq.Gate') -> None:
"""Initialize with a noise gate applied to each qubit."""
def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE':
"""Add qubit noise after the operation."""Noise model derived from detailed noise characterization.
class NoiseModelFromNoiseProperties(NoiseModel):
"""Noise model derived from noise properties."""
def __init__(self, noise_properties: 'NoiseProperties') -> None:
"""Initialize from noise properties characterization."""
def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE':
"""Apply noise based on operation type and noise properties."""Noise model that inserts noise operations at specified locations.
class InsertionNoiseModel(NoiseModel):
"""Noise model that inserts noise operations."""
def __init__(self, ops_added: Dict[OpIdentifier, 'cirq.OP_TREE']) -> None:
"""Initialize with operations to add for each gate type."""
def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE':
"""Insert additional noise operations."""Thermal noise model for quantum operations.
class ThermalNoiseModel(NoiseModel):
"""Thermal noise model for quantum operations."""
def __init__(self, frozen_pi_hats: Dict['cirq.Qid', np.ndarray],
decay_constants: Dict['cirq.Qid', float],
gate_times: Dict[type, 'cirq.Duration']) -> None:
"""Initialize thermal noise model."""
def noisy_operation(self, operation: 'cirq.Operation') -> 'cirq.OP_TREE':
"""Apply thermal noise during gate operation."""Properties characterizing noise in quantum operations.
class NoiseProperties:
"""Properties characterizing noise in quantum operations."""
def __init__(self,
gate_times_ns: Dict[type, float],
t1_ns: Dict['cirq.Qid', float],
t2_ns: Dict['cirq.Qid', float],
readout_errors: Dict['cirq.Qid', Tuple[float, float]],
gate_pauli_errors: Dict['cirq.Qid', Dict[type, float]]) -> None:
"""Initialize noise properties."""
@property
def gate_times_ns(self) -> Dict[type, float]:
"""Gate execution times in nanoseconds."""
@property
def t1_ns(self) -> Dict['cirq.Qid', float]:
"""T1 coherence times in nanoseconds."""
@property
def t2_ns(self) -> Dict['cirq.Qid', float]:
"""T2 dephasing times in nanoseconds."""
@property
def readout_errors(self) -> Dict['cirq.Qid', Tuple[float, float]]:
"""Readout error probabilities (p01, p10)."""
@property
def gate_pauli_errors(self) -> Dict['cirq.Qid', Dict[type, float]]:
"""Pauli error rates for different gate types."""Specialized noise properties for superconducting qubits.
class SuperconductingQubitsNoiseProperties(NoiseProperties):
"""Noise properties for superconducting qubits."""
def __init__(self,
t1_ns: Dict['cirq.Qid', float],
tphi_ns: Dict['cirq.Qid', float],
readout_errors: Dict['cirq.Qid', Tuple[float, float]],
gate_pauli_errors: Dict['cirq.Qid', Dict[type, float]] = None) -> None:
"""Initialize superconducting qubit noise properties."""
@classmethod
def from_default_noise_model(cls, qubits: Iterable['cirq.Qid']) -> 'SuperconductingQubitsNoiseProperties':
"""Create default noise model for superconducting qubits."""Identifier for operations in noise models.
class OpIdentifier:
"""Identifier for operations in noise models."""
def __init__(self, gate_type: type, *qubits: 'cirq.Qid') -> None:
"""Initialize operation identifier."""
@property
def gate_type(self) -> type:
"""Type of the gate."""
@property
def qubits(self) -> Tuple['cirq.Qid', ...]:
"""Qubits the operation acts on."""Abstract base class for named device topologies.
class NamedTopology:
"""Abstract base class for named device topologies."""
@abc.abstractmethod
def nodes(self) -> Set[Any]:
"""Nodes in the topology."""
@abc.abstractmethod
def edges(self) -> Set[Tuple[Any, Any]]:
"""Edges in the topology."""
def neighbors_of(self, node: Any) -> Set[Any]:
"""Get neighbors of a node."""Linear arrangement of qubits.
class LineTopology(NamedTopology):
"""Linear arrangement of qubits."""
def __init__(self, length: int) -> None:
"""Initialize line topology with given length."""
def nodes(self) -> Set[int]:
"""Node indices in the line."""
def edges(self) -> Set[Tuple[int, int]]:
"""Adjacent pairs in the line."""Tilted square lattice topology.
class TiltedSquareLattice(NamedTopology):
"""Tilted square lattice topology."""
def __init__(self, rows: int, cols: int) -> None:
"""Initialize tilted square lattice."""
def nodes(self) -> Set[Tuple[int, int]]:
"""Grid positions in the lattice."""
def edges(self) -> Set[Tuple[Tuple[int, int], Tuple[int, int]]]:
"""Connected pairs in the lattice."""NO_NOISE: NoiseModel
"""No-noise model constant."""
NOISE_MODEL_LIKE = Union[NoiseModel, 'cirq.Gate', Callable[['cirq.Operation'], 'cirq.OP_TREE']]
"""Type hint for noise model-like objects."""def draw_gridlike(qubits: Iterable[GridQubit],
ax: Optional['matplotlib.axes.Axes'] = None,
tilted: bool = True) -> 'matplotlib.axes.Axes':
"""Draw grid-like device layout."""def get_placements(topology: NamedTopology,
circuit_qubits: Sequence['cirq.Qid']) -> List[Dict['cirq.Qid', Any]]:
"""Get valid qubit placements on topology."""
def is_valid_placement(topology: NamedTopology,
qubit_mapping: Dict['cirq.Qid', Any]) -> bool:
"""Check if qubit placement is valid."""
def draw_placements(topology: NamedTopology,
qubit_mapping: Dict['cirq.Qid', Any]) -> None:
"""Visualize qubit placements."""def decay_constant_to_xeb_fidelity(decay_constant: float, num_qubits: int) -> float:
"""Convert decay constant to XEB fidelity."""
def decay_constant_to_pauli_error(decay_constant: float) -> float:
"""Convert decay constant to Pauli error."""
def pauli_error_to_decay_constant(pauli_error: float) -> float:
"""Convert Pauli error to decay constant."""
def xeb_fidelity_to_decay_constant(xeb_fidelity: float, num_qubits: int) -> float:
"""Convert XEB fidelity to decay constant."""
def pauli_error_from_t1(t1: float, gate_time: float) -> float:
"""Calculate Pauli error from T1 time."""
def average_error(errors: Iterable[float]) -> float:
"""Calculate average error rate."""
def decoherence_pauli_error(t1: float, t2: float, gate_time: float) -> float:
"""Calculate decoherence Pauli error."""import cirq
# Line qubits for 1D topologies
line_qubits = cirq.LineQubit.range(5)
print(f"Line qubits: {line_qubits}")
# Grid qubits for 2D topologies
grid_qubits = cirq.GridQubit.rect(3, 3)
print(f"Grid qubits: {grid_qubits}")
# Check adjacency
q0, q1 = cirq.GridQubit(0, 0), cirq.GridQubit(0, 1)
print(f"Adjacent: {q0.is_adjacent(q1)}")
print(f"Neighbors of {q0}: {q0.neighbors()}")import cirq
# Create a simple circuit
qubits = cirq.LineQubit.range(2)
circuit = cirq.Circuit([
cirq.H(qubits[0]),
cirq.CNOT(qubits[0], qubits[1])
])
# Apply depolarizing noise
noise_model = cirq.ConstantQubitNoiseModel(cirq.depolarize(p=0.01))
noisy_circuit = circuit.with_noise(noise_model)
print("Original circuit:")
print(circuit)
print("\nNoisy circuit:")
print(noisy_circuit)import cirq
class MyDevice(cirq.Device):
def __init__(self, qubits):
self._qubits = frozenset(qubits)
def qubits(self):
return self._qubits
def validate_operation(self, operation):
if not set(operation.qubits).issubset(self._qubits):
raise ValueError(f"Operation {operation} uses invalid qubits")
# Add custom validation logic here
# Create device and validate circuit
qubits = cirq.LineQubit.range(3)
device = MyDevice(qubits)
circuit = cirq.Circuit(cirq.H(qubits[0]))
try:
device.validate_circuit(circuit)
print("Circuit is valid for device")
except ValueError as e:
print(f"Invalid circuit: {e}")This documentation provides comprehensive coverage of device modeling and noise simulation capabilities in Cirq for realistic NISQ quantum computing.
Install with Tessl CLI
npx tessl i tessl/pypi-cirq