scientific-skills/cirq/references/simulation.md
This guide covers quantum circuit simulation, including exact and noisy simulations, parameter sweeps, and the Quantum Virtual Machine (QVM).
import cirq
import numpy as np
# Create circuit
q0, q1 = cirq.LineQubit.range(2)
circuit = cirq.Circuit(
cirq.H(q0),
cirq.CNOT(q0, q1),
cirq.measure(q0, q1, key='result')
)
# Simulate
simulator = cirq.Simulator()
result = simulator.run(circuit, repetitions=1000)
# Get measurement results
print(result.histogram(key='result'))
# Simulate without measurement to get final state
simulator = cirq.Simulator()
result = simulator.simulate(circuit_without_measurement)
# Access state vector
state_vector = result.final_state_vector
print(f"State vector: {state_vector}")
# Get amplitudes
print(f"Amplitude of |00⟩: {state_vector[0]}")
print(f"Amplitude of |11⟩: {state_vector[3]}")
# Use density matrix simulator for mixed states
simulator = cirq.DensityMatrixSimulator()
result = simulator.simulate(circuit)
# Access density matrix
density_matrix = result.final_density_matrix
print(f"Density matrix shape: {density_matrix.shape}")
# Simulate moment-by-moment
simulator = cirq.Simulator()
for step in simulator.simulate_moment_steps(circuit):
print(f"State after moment {step.moment}: {step.state_vector()}")
# Run circuit multiple times
result = simulator.run(circuit, repetitions=10000)
# Access measurement counts
counts = result.histogram(key='result')
print(f"Measurement counts: {counts}")
# Get raw measurements
measurements = result.measurements['result']
print(f"Shape: {measurements.shape}") # (repetitions, num_qubits)
# Measure observable expectation value
from cirq import PauliString
observable = PauliString({q0: cirq.Z, q1: cirq.Z})
result = simulator.simulate_expectation_values(
circuit,
observables=[observable]
)
print(f"⟨ZZ⟩ = {result[0]}")
import sympy
# Create parameterized circuit
theta = sympy.Symbol('theta')
q = cirq.LineQubit(0)
circuit = cirq.Circuit(
cirq.ry(theta)(q),
cirq.measure(q, key='m')
)
# Define parameter sweep
sweep = cirq.Linspace(key='theta', start=0, stop=2*np.pi, length=50)
# Run sweep
simulator = cirq.Simulator()
results = simulator.run_sweep(circuit, params=sweep, repetitions=1000)
# Process results
for params, result in zip(sweep, results):
theta_val = params['theta']
counts = result.histogram(key='m')
print(f"θ={theta_val:.2f}: {counts}")
# Sweep over multiple parameters
theta = sympy.Symbol('theta')
phi = sympy.Symbol('phi')
circuit = cirq.Circuit(
cirq.ry(theta)(q0),
cirq.rz(phi)(q1)
)
# Product sweep (all combinations)
sweep = cirq.Product(
cirq.Linspace('theta', 0, np.pi, 10),
cirq.Linspace('phi', 0, 2*np.pi, 10)
)
results = simulator.run_sweep(circuit, params=sweep, repetitions=100)
# Sweep parameters together
sweep = cirq.Zip(
cirq.Linspace('theta', 0, np.pi, 20),
cirq.Linspace('phi', 0, 2*np.pi, 20)
)
results = simulator.run_sweep(circuit, params=sweep, repetitions=100)
# Create noisy circuit
noisy_circuit = circuit.with_noise(cirq.depolarize(p=0.01))
# Simulate noisy circuit
simulator = cirq.DensityMatrixSimulator()
result = simulator.run(noisy_circuit, repetitions=1000)
# Apply different noise to different gates
noise_model = cirq.NoiseModel.from_noise_model_like(
cirq.ConstantQubitNoiseModel(cirq.depolarize(0.01))
)
# Simulate with noise model
result = cirq.DensityMatrixSimulator(noise=noise_model).run(
circuit, repetitions=1000
)
See noise.md for comprehensive noise modeling details.
import matplotlib.pyplot as plt
# Get histogram
result = simulator.run(circuit, repetitions=1000)
counts = result.histogram(key='result')
# Plot
plt.bar(counts.keys(), counts.values())
plt.xlabel('State')
plt.ylabel('Counts')
plt.title('Measurement Results')
plt.show()
# Get state vector
result = simulator.simulate(circuit_without_measurement)
state_vector = result.final_state_vector
# Compute probabilities
probabilities = np.abs(state_vector) ** 2
# Plot
plt.bar(range(len(probabilities)), probabilities)
plt.xlabel('Basis State Index')
plt.ylabel('Probability')
plt.show()
QVM simulates realistic quantum hardware with device-specific constraints and noise.
# Use a virtual Google device
import cirq_google
# Get virtual device
device = cirq_google.Sycamore
# Create circuit on device
qubits = device.metadata.qubit_set
circuit = cirq.Circuit(device=device)
# Add operations respecting device constraints
circuit.append(cirq.CZ(qubits[0], qubits[1]))
# Validate circuit against device
device.validate_circuit(circuit)
# Simulate with device noise
processor = cirq_google.get_engine().get_processor('weber')
noise_props = processor.get_device_specification()
# Create realistic noisy simulator
noisy_sim = cirq.DensityMatrixSimulator(
noise=cirq_google.NoiseModelFromGoogleNoiseProperties(noise_props)
)
result = noisy_sim.run(circuit, repetitions=1000)
# Start from custom state
initial_state = np.array([1, 0, 0, 1]) / np.sqrt(2) # |00⟩ + |11⟩
simulator = cirq.Simulator()
result = simulator.simulate(circuit, initial_state=initial_state)
# Trace out subsystems
result = simulator.simulate(circuit)
full_state = result.final_state_vector
# Compute reduced density matrix for first qubit
from cirq import partial_trace
reduced_dm = partial_trace(result.final_density_matrix, keep_indices=[0])
# Get state at specific moment
simulator = cirq.Simulator()
for i, step in enumerate(simulator.simulate_moment_steps(circuit)):
if i == 5: # After 5th moment
state = step.state_vector()
print(f"State after moment 5: {state}")
break
# Efficient: Single sweep
results = simulator.run_sweep(circuit, params=sweep, repetitions=100)
# Inefficient: Multiple individual runs
results = [simulator.run(circuit, param_resolver=p, repetitions=100)
for p in sweep]
# For large systems, monitor state vector size
n_qubits = 20
state_size = 2**n_qubits * 16 # bytes (complex128)
print(f"State vector size: {state_size / 1e9:.2f} GB")
For circuits with only Clifford gates, use efficient stabilizer simulation:
# Clifford circuit (H, S, CNOT)
circuit = cirq.Circuit(
cirq.H(q0),
cirq.S(q1),
cirq.CNOT(q0, q1)
)
# Use stabilizer simulator (exponentially faster)
simulator = cirq.CliffordSimulator()
result = simulator.run(circuit, repetitions=1000)