Skip to content

Advanced Examples

Advanced examples demonstrating QPyth's capabilities.

Custom VQE Implementation

Custom Ansatz

from qiskit import QuantumCircuit, ParameterVector
from qiskit_algorithms.optimizers import SPSA
from qiskit_aer import AerSimulator
import numpy as np

def custom_ansatz(num_qubits, depth):
    """Create custom parameterized ansatz."""
    qc = QuantumCircuit(num_qubits)
    params = ParameterVector('θ', num_qubits * depth)

    for d in range(depth):
        # Rotation layer
        for i in range(num_qubits):
            qc.ry(params[d * num_qubits + i], i)

        # Entanglement layer
        for i in range(num_qubits - 1):
            qc.cx(i, i + 1)

    return qc

# Create ansatz
ansatz = custom_ansatz(num_qubits=2, depth=3)
print(ansatz)

Custom Optimizer

from qiskit_algorithms.optimizers import SPSA, COBYLA, SLSQP
from qiskit_algorithms import VQE
from qiskit.primitives import Estimator

# Define cost function
def cost_function(params):
    # Your cost function here
    return np.sum(params ** 2)

# Use SPSA optimizer (robust for noisy environments)
optimizer = SPSA(maxiter=100)

# Use COBYLA optimizer
optimizer = COBYLA(maxiter=100)

# Use SLSQP optimizer
optimizer = SLSQP(maxiter=100)

# Optimize
initial_params = np.random.rand(10)
result = optimizer.minimize(cost_function, x0=initial_params)
print(f"Optimized parameters: {result.x}")
print(f"Minimum value: {result.fun}")

Multi-Molecule VQE

from quantumpytho.modules.vqe_molecules import list_molecules, get_molecule
from quantumpytho.modules.vqe_core import run_vqe_molecule

# Get available molecules
molecules = list_molecules()
print(f"Available molecules: {molecules}")

# Run VQE for each molecule
results = {}
for mol_name in molecules:
    print(f"\nRunning VQE for {mol_name}...")
    result = run_vqe_molecule(mol_name, max_iters=50)
    results[mol_name] = result
    print(f"Final energy: {result['final_energy']:.6f} Hartree")

Advanced Noise Modeling

Custom Noise Model

from qiskit_aer.noise import NoiseModel, errors
from qiskit_aer import AerSimulator

# Create noise model
noise_model = NoiseModel()

# Add depolarizing error to single-qubit gates
error_1q = errors.depolarizing_error(0.001, 1)
for gate in ['h', 'x', 'y', 'z', 'rx', 'ry', 'rz']:
    noise_model.add_all_qubit_quantum_error(error_1q, gate)

# Add depolarizing error to two-qubit gates
error_2q = errors.depolarizing_error(0.01, 2)
for gate in ['cx', 'cz']:
    noise_model.add_all_qubit_quantum_error(error_2q, gate)

# Add readout error
readout_error = errors.readout_error([[0.99, 0.01], [0.02, 0.98]])
noise_model.add_all_qubit_readout_error(readout_error)

# Use with simulator
simulator = AerSimulator(noise_model=noise_model)

Thermal Relaxation Error

from qiskit_aer.noise import NoiseModel, errors
import numpy as np

# Create noise model with thermal relaxation
noise_model = NoiseModel()

# T1 and T2 times (in microseconds)
t1 = 100.0
t2 = 80.0
gate_time = 0.1  # Gate time in microseconds

# Calculate thermal relaxation error
# Error probability = 1 - exp(-gate_time/T1)
p_reset = 1 - np.exp(-gate_time / t1)

# Add thermal relaxation error
thermal_error = errors.thermal_relaxation_error(t1, t2, gate_time)
noise_model.add_all_qubit_quantum_error(thermal_error, ['h', 'x', 'y', 'z'])

# Use with simulator
from qiskit_aer import AerSimulator
simulator = AerSimulator(noise_model=noise_model)

Correlated Noise

from qiskit_aer.noise import NoiseModel, errors

# Create noise model with correlated errors
noise_model = NoiseModel()

# Create correlated readout error
# Probability of measuring 0 when actual is 0: 0.99
# Probability of measuring 1 when actual is 0: 0.01
# Probability of measuring 0 when actual is 1: 0.02
# Probability of measuring 1 when actual is 1: 0.98
correlated_readout = errors.readout_error(
    [[0.99, 0.01], [0.02, 0.98]]
)
noise_model.add_all_qubit_readout_error(correlated_readout)

# Use with simulator
from qiskit_aer import AerSimulator
simulator = AerSimulator(noise_model=noise_model)

Error Mitigation

Measurement Error Mitigation

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
from qiskit.visualization import plot_histogram
import matplotlib.pyplot as plt

# Create circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

# Run without mitigation
simulator = AerSimulator()
result_no_mitigation = simulator.run(qc, shots=1024).result()
counts_no_mitigation = result_no_mitigation.get_counts()

# Run with measurement error mitigation
simulator_mitigated = AerSimulator(
    mitigation_config={"measure_mitigation": True}
)
result_mitigated = simulator_mitigated.run(qc, shots=1024).result()
counts_mitigated = result_mitigated.get_counts()

# Compare results
print("Without mitigation:", counts_no_mitigation)
print("With mitigation:", counts_mitigated)

# Plot comparison
plot_histogram([counts_no_mitigation, counts_mitigated],
               legend=['No Mitigation', 'With Mitigation'])
plt.show()

Zero Noise Extrapolation

from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator
import numpy as np

# Create circuit
qc = QuantumCircuit(2)
qc.h(0)
qc.cx(0, 1)
qc.measure_all()

# Run at different noise levels
noise_factors = [1.0, 2.0, 3.0]
results = []

for factor in noise_factors:
    # Scale noise
    simulator = AerSimulator(
        noise_model=noise_model,
        noise_scale_factor=factor
    )
    result = simulator.run(qc, shots=1024).result()
    counts = result.get_counts()
    results.append(counts)

# Extrapolate to zero noise
# (simplified example)
# In practice, use more sophisticated extrapolation methods
print("Results at different noise levels:")
for i, counts in enumerate(results):
    print(f"Noise factor {noise_factors[i]}: {counts}")

Advanced QEC

Concatenated Codes

from qiskit import QuantumCircuit

def concatenate_shor_code(logical_qubit):
    """Concatenate Shor's code with itself."""
    # Outer encoding: 1 logical -> 9 physical
    outer_qubits = list(range(9))

    # Inner encoding: each of 9 -> 9 more
    # Total: 81 physical qubits
    inner_qubits = []
    for i in range(9):
        start = i * 9
        inner_qubits.append(list(range(start, start + 9)))

    # Create circuit
    qc = QuantumCircuit(81)

    # Outer encoding
    # ... (encoding circuit)

    # Inner encoding for each block
    for block in inner_qubits:
        # ... (encoding circuit for each block)

    return qc

# Create concatenated code
qc = concatenate_shor_code(0)
print(f"Concatenated code uses {qc.num_qubits} qubits")

Fault-Tolerant Gates

from qiskit import QuantumCircuit

def transversal_cnot(control, target):
    """Apply transversal CNOT for Steane's code."""
    qc = QuantumCircuit(14)  # 7 qubits each

    # Apply CNOT transversally
    for i in range(7):
        qc.cx(control[i], target[i])

    return qc

# Create transversal CNOT
control = list(range(7))
target = list(range(7, 14))
qc = transversal_cnot(control, target)
print(qc)

Bond Distance Scanning

H2 Bond Distance Scan

from quantumpytho.modules.vqe_utils import scan_h2_bond_distances

# Scan bond distances
result = scan_h2_bond_distances(
    distances=[0.5, 0.6, 0.735, 0.8, 0.9, 1.0],
    max_iters=50
)

print(f"Equilibrium distance: {result['equilibrium_distance']:.3f} Å")
print(f"Minimum energy: {result['min_energy']:.6f} Hartree")

# Plot energy curve
import matplotlib.pyplot as plt

plt.plot(result['distances'], result['energies'], 'o-')
plt.xlabel('Bond Distance (Å)')
plt.ylabel('Energy (Hartree)')
plt.title('H2 Energy vs Bond Distance')
plt.grid(True)
plt.show()

Custom Molecule Scan

from quantumpytho.modules.vqe_molecules import scan_bond_distance

# Scan LiH bond distance
result = scan_bond_distance(
    name="LiH",
    distances=[1.4, 1.5, 1.595, 1.7, 1.8],
    max_iters=50
)

print(f"Equilibrium distance: {result['equilibrium_distance']:.3f} Å")
print(f"Minimum energy: {result['min_energy']:.6f} Hartree")

Hardware Integration

Backend Selection

from quantumpytho.modules.hardware_ibm import IBMHardwareEngine

# Connect to IBM Quantum
engine = IBMHardwareEngine()
engine.connect()

# List all backends
backends = engine.list_backends()
print("Available backends:")
for backend in backends:
    print(f"  {backend['name']}: {backend['num_qubits']} qubits")

# Select least busy backend with at least 5 qubits
selected = engine.select_backend(min_qubits=5, least_busy=True)
print(f"\nSelected backend: {selected}")

# Get backend info
info = engine.get_backend_info(selected)
print(f"Queue: {info['pending_jobs']} jobs")
print(f"Operations: {info['operations']}")

Job Monitoring

from qiskit_ibm_runtime import QiskitRuntimeService
import time

# Connect to service
service = QiskitRuntimeService()

# Get job
job = service.job("your-job-id")

# Monitor job status
while job.status() not in ['DONE', 'CANCELLED', 'ERROR']:
    print(f"Status: {job.status()}")
    time.sleep(10)

# Get results
result = job.result()
print(f"Job completed: {job.status()}")

Performance Optimization

Circuit Optimization

from qiskit import QuantumCircuit, transpile
from qiskit_aer import AerSimulator

# Create circuit
qc = QuantumCircuit(5)
qc.h(0)
for i in range(4):
    qc.cx(i, i+1)
qc.measure_all()

# Optimize for specific backend
backend = AerSimulator()
optimized_qc = transpile(qc, backend=backend, optimization_level=3)

print(f"Original depth: {qc.depth()}")
print(f"Optimized depth: {optimized_qc.depth()}")

Parallel Execution

from concurrent.futures import ThreadPoolExecutor
from qiskit import QuantumCircuit
from qiskit_aer import AerSimulator

def run_circuit(params):
    """Run circuit with given parameters."""
    qc = QuantumCircuit(2)
    qc.ry(params[0], 0)
    qc.ry(params[1], 1)
    qc.cx(0, 1)
    qc.measure_all()

    simulator = AerSimulator()
    result = simulator.run(qc, shots=1024).result()
    return result.get_counts()

# Run multiple circuits in parallel
param_sets = [
    [0.0, 0.0],
    [1.57, 1.57],
    [3.14, 3.14]
]

with ThreadPoolExecutor(max_workers=3) as executor:
    results = list(executor.map(run_circuit, param_sets))

for i, counts in enumerate(results):
    print(f"Params {param_sets[i]}: {counts}")

Next Steps