mirror of
https://github.com/K-Dense-AI/claude-scientific-skills.git
synced 2026-01-26 16:58:56 +08:00
13 KiB
13 KiB
Devices and Backends in PennyLane
Table of Contents
- Built-in Simulators
- Hardware Plugins
- Device Selection
- Device Configuration
- Custom Devices
- Performance Optimization
Built-in Simulators
default.qubit
General-purpose state vector simulator:
import pennylane as qml
# Basic initialization
dev = qml.device('default.qubit', wires=4)
# With shots (sampling mode)
dev = qml.device('default.qubit', wires=4, shots=1000)
# Specify wire labels
dev = qml.device('default.qubit', wires=['a', 'b', 'c', 'd'])
default.mixed
Mixed-state simulator for noisy quantum systems:
# Supports density matrix simulation
dev = qml.device('default.mixed', wires=2)
@qml.qnode(dev)
def noisy_circuit():
qml.Hadamard(wires=0)
# Apply noise
qml.DepolarizingChannel(0.1, wires=0)
qml.CNOT(wires=[0, 1])
# Amplitude damping
qml.AmplitudeDamping(0.05, wires=1)
return qml.expval(qml.PauliZ(0))
default.qubit.torch, default.qubit.tf, default.qubit.jax
Framework-specific simulators with better integration:
# PyTorch
dev = qml.device('default.qubit.torch', wires=4)
# TensorFlow
dev = qml.device('default.qubit.tf', wires=4)
# JAX
dev = qml.device('default.qubit.jax', wires=4)
lightning.qubit
High-performance C++ simulator:
# Faster than default.qubit
dev = qml.device('lightning.qubit', wires=20)
# Supports larger systems efficiently
@qml.qnode(dev)
def large_circuit():
for i in range(20):
qml.Hadamard(wires=i)
for i in range(19):
qml.CNOT(wires=[i, i+1])
return qml.expval(qml.PauliZ(0))
default.clifford
Efficient simulator for Clifford circuits:
# Only supports Clifford gates (H, S, CNOT, etc.)
dev = qml.device('default.clifford', wires=100)
@qml.qnode(dev)
def clifford_circuit():
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
qml.S(wires=1)
# Cannot use RX, RY, RZ, etc.
return qml.expval(qml.PauliZ(0))
Hardware Plugins
IBM Quantum (Qiskit)
# Install plugin
uv pip install pennylane-qiskit
import pennylane as qml
# Use IBM simulator
dev = qml.device('qiskit.aer', wires=2)
# Use IBM quantum hardware
dev = qml.device(
'qiskit.ibmq',
wires=2,
backend='ibmq_manila', # Specify backend
shots=1024
)
# With API token
dev = qml.device(
'qiskit.ibmq',
wires=2,
backend='ibmq_manila',
ibmqx_token='YOUR_API_TOKEN'
)
@qml.qnode(dev)
def circuit():
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0))
Amazon Braket
# Install plugin
uv pip install amazon-braket-pennylane-plugin
# Use Braket simulators
dev = qml.device(
'braket.local.qubit',
wires=2
)
# Use AWS simulators
dev = qml.device(
'braket.aws.qubit',
device_arn='arn:aws:braket:::device/quantum-simulator/amazon/sv1',
wires=4,
s3_destination_folder=('amazon-braket-outputs', 'outputs')
)
# Use quantum hardware (IonQ, Rigetti, etc.)
dev = qml.device(
'braket.aws.qubit',
device_arn='arn:aws:braket:us-east-1::device/qpu/ionq/Harmony',
wires=11,
shots=1000,
s3_destination_folder=('amazon-braket-outputs', 'outputs')
)
Google Cirq
# Install plugin
uv pip install pennylane-cirq
# Use Cirq simulator
dev = qml.device('cirq.simulator', wires=2)
# Use Cirq with qsim (faster)
dev = qml.device('cirq.qsim', wires=20)
# Use Google quantum hardware (if you have access)
dev = qml.device(
'cirq.pasqal',
wires=2,
device='rainbow',
shots=1000
)
Rigetti Forest
# Install plugin
uv pip install pennylane-rigetti
# Use QVM (Quantum Virtual Machine)
dev = qml.device('rigetti.qvm', device='4q-qvm', shots=1000)
# Use Rigetti QPU
dev = qml.device('rigetti.qpu', device='Aspen-M-3', shots=1000)
Microsoft Azure Quantum
# Install plugin
uv pip install pennylane-azure
# Use Azure simulators
dev = qml.device(
'azure.simulator',
wires=4,
workspace='your-workspace',
resource_group='your-resource-group',
subscription_id='your-subscription-id'
)
# Use IonQ on Azure
dev = qml.device(
'azure.ionq',
wires=11,
workspace='your-workspace',
resource_group='your-resource-group',
subscription_id='your-subscription-id',
shots=500
)
IonQ
# Install plugin
uv pip install pennylane-ionq
# Use IonQ hardware
dev = qml.device(
'ionq.simulator', # or 'ionq.qpu'
wires=11,
shots=1024,
api_key='your_api_key'
)
Xanadu Hardware (Borealis)
# Photonic quantum computer
dev = qml.device(
'strawberryfields.remote',
backend='borealis',
shots=10000
)
Device Selection
Choosing the Right Device
def select_device(n_qubits, use_hardware=False, noise_model=None):
"""Select appropriate device based on requirements."""
if use_hardware:
# Use real quantum hardware
if n_qubits <= 11:
return qml.device('ionq.qpu', wires=n_qubits, shots=1000)
elif n_qubits <= 127:
return qml.device('qiskit.ibmq', wires=n_qubits, shots=1024)
else:
raise ValueError(f"No hardware available for {n_qubits} qubits")
elif noise_model:
# Use noisy simulator
return qml.device('default.mixed', wires=n_qubits)
else:
# Use ideal simulator
if n_qubits <= 20:
return qml.device('lightning.qubit', wires=n_qubits)
else:
return qml.device('default.qubit', wires=n_qubits)
# Usage
dev = select_device(n_qubits=10, use_hardware=False)
Device Capabilities
# Check device capabilities
dev = qml.device('default.qubit', wires=4)
print("Device name:", dev.name)
print("Number of wires:", dev.num_wires)
print("Supports shots:", dev.shots is not None)
# Check supported operations
print("Supported gates:", dev.operations)
# Check supported observables
print("Supported observables:", dev.observables)
Device Configuration
Setting Shots
# Exact simulation (no shots)
dev = qml.device('default.qubit', wires=2)
@qml.qnode(dev)
def exact_circuit():
qml.Hadamard(wires=0)
return qml.expval(qml.PauliZ(0))
result = exact_circuit() # Returns exact expectation
# Sampling mode (with shots)
dev_sampled = qml.device('default.qubit', wires=2, shots=1000)
@qml.qnode(dev_sampled)
def sampled_circuit():
qml.Hadamard(wires=0)
return qml.expval(qml.PauliZ(0))
result = sampled_circuit() # Estimated from samples
Dynamic Shots
# Change shots per execution
dev = qml.device('default.qubit', wires=2)
@qml.qnode(dev)
def circuit():
qml.Hadamard(wires=0)
return qml.expval(qml.PauliZ(0))
# Different shot numbers
result_100 = circuit(shots=100)
result_1000 = circuit(shots=1000)
result_exact = circuit(shots=None) # Exact
Analytic Mode vs Finite Shots
# Compare analytic vs sampled
dev_analytic = qml.device('default.qubit', wires=2)
dev_sampled = qml.device('default.qubit', wires=2, shots=1000)
@qml.qnode(dev_analytic)
def circuit_analytic(x):
qml.RX(x, wires=0)
return qml.expval(qml.PauliZ(0))
@qml.qnode(dev_sampled)
def circuit_sampled(x):
qml.RX(x, wires=0)
return qml.expval(qml.PauliZ(0))
import numpy as np
x = np.pi / 4
print(f"Analytic: {circuit_analytic(x)}")
print(f"Sampled: {circuit_sampled(x)}")
print(f"Exact value: {np.cos(x)}")
Seed for Reproducibility
# Set random seed
dev = qml.device('default.qubit', wires=2, shots=1000, seed=42)
@qml.qnode(dev)
def circuit():
qml.Hadamard(wires=0)
return qml.sample(qml.PauliZ(0))
# Reproducible results
samples1 = circuit()
samples2 = circuit() # Same as samples1 if seed is set
Custom Devices
Creating a Custom Device
from pennylane.devices import DefaultQubit
class CustomDevice(DefaultQubit):
"""Custom quantum device with additional features."""
name = 'Custom device'
short_name = 'custom'
pennylane_requires = '>=0.30.0'
version = '0.1.0'
author = 'Your Name'
def __init__(self, wires, shots=None, **kwargs):
super().__init__(wires=wires, shots=shots)
# Custom initialization
def apply(self, operations, **kwargs):
"""Apply operations with custom logic."""
# Custom operation handling
for op in operations:
# Log or modify operations
print(f"Applying: {op.name}")
# Call parent implementation
super().apply(operations, **kwargs)
# Use custom device
dev = CustomDevice(wires=4)
Plugin Development
# Define custom plugin operations
class CustomGate(qml.operation.Operation):
"""Custom quantum gate."""
num_wires = 1
num_params = 1
par_domain = 'R'
def decomposition(self):
"""Decompose into standard gates."""
theta = self.parameters[0]
wires = self.wires
return [
qml.RY(theta / 2, wires=wires),
qml.RZ(theta, wires=wires),
qml.RY(-theta / 2, wires=wires)
]
# Register with device
qml.ops.CustomGate = CustomGate
Performance Optimization
Batch Execution
# Execute multiple parameter sets efficiently
dev = qml.device('default.qubit', wires=2)
@qml.qnode(dev)
def circuit(params):
qml.RX(params[0], wires=0)
qml.RY(params[1], wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0))
# Batch parameters
params_batch = np.random.random((100, 2))
# Vectorized execution (faster)
results = [circuit(p) for p in params_batch]
Device Caching
# Cache device for reuse
_device_cache = {}
def get_device(n_qubits, device_type='default.qubit'):
"""Get or create cached device."""
key = (device_type, n_qubits)
if key not in _device_cache:
_device_cache[key] = qml.device(device_type, wires=n_qubits)
return _device_cache[key]
# Reuse devices
dev1 = get_device(4)
dev2 = get_device(4) # Returns same device
JIT Compilation with Catalyst
# Install Catalyst
# uv pip install pennylane-catalyst
import pennylane as qml
from catalyst import qjit
dev = qml.device('lightning.qubit', wires=4)
@qjit # Just-in-time compilation
@qml.qnode(dev)
def compiled_circuit(x):
qml.RX(x, wires=0)
qml.Hadamard(wires=1)
qml.CNOT(wires=[0, 1])
return qml.expval(qml.PauliZ(0))
# First call compiles, subsequent calls are fast
result = compiled_circuit(0.5)
Parallel Execution
from multiprocessing import Pool
def run_circuit(params):
"""Run circuit with given parameters."""
dev = qml.device('default.qubit', wires=4)
@qml.qnode(dev)
def circuit(p):
# Circuit definition
return qml.expval(qml.PauliZ(0))
return circuit(params)
# Parallel execution
param_list = [np.random.random(10) for _ in range(100)]
with Pool(processes=4) as pool:
results = pool.map(run_circuit, param_list)
GPU Acceleration
# Use GPU-accelerated devices if available
try:
dev = qml.device('lightning.gpu', wires=20)
except:
dev = qml.device('lightning.qubit', wires=20)
@qml.qnode(dev)
def gpu_circuit():
# Large circuit benefits from GPU
for i in range(20):
qml.Hadamard(wires=i)
for i in range(19):
qml.CNOT(wires=[i, i+1])
return [qml.expval(qml.PauliZ(i)) for i in range(20)]
Best Practices
- Start with simulators - Test on
default.qubitbefore hardware - Use lightning for speed - Switch to
lightning.qubitfor larger circuits - Match device to task - Use
default.mixedfor noise studies - Cache devices - Reuse device objects to avoid initialization overhead
- Set appropriate shots - Balance accuracy vs speed
- Check capabilities - Verify device supports required operations
- Handle hardware errors - Implement retries and error mitigation
- Monitor costs - Track hardware usage and costs
- Use JIT when possible - Compile circuits with Catalyst for speedup
- Test locally first - Validate on simulators before submitting to hardware
Device Comparison
| Device | Type | Max Qubits | Speed | Noise | Use Case |
|---|---|---|---|---|---|
| default.qubit | Simulator | ~25 | Medium | No | General purpose |
| lightning.qubit | Simulator | ~30 | Fast | No | Large circuits |
| default.mixed | Simulator | ~15 | Slow | Yes | Noise studies |
| default.clifford | Simulator | 100+ | Very fast | No | Clifford circuits |
| IBM Quantum | Hardware | 127 | Slow | Yes | Real experiments |
| IonQ | Hardware | 11 | Slow | Low | High fidelity |
| Rigetti | Hardware | 80 | Slow | Yes | Research |
| Borealis | Hardware | 216 | Slow | Yes | Photonic QC |