Complete Cirq Framework Cheatsheet: Quantum Circuit Programming Guide

Introduction to Cirq

Cirq is Google’s open-source framework for programming quantum computers. It provides tools for creating, manipulating, and optimizing quantum circuits, then running them on quantum hardware or simulators. Cirq is designed with near-term quantum processors in mind, focusing on the constraints of existing quantum hardware. As quantum computing continues to advance, Cirq offers researchers and developers a flexible platform to experiment with quantum algorithms and applications.

Core Concepts & Components

Qubits and QubitIds

Qubits in Cirq are represented by various qubit types:

# Common qubit types
import cirq

# LineQubit: 1D array of qubits with integer indices
q0 = cirq.LineQubit(0)
line_qubits = cirq.LineQubit.range(3)  # Creates qubits 0, 1, and 2

# GridQubit: 2D array of qubits with (row, col) indices
grid_qubit = cirq.GridQubit(2, 3)  # Qubit at row 2, column 3
grid_qubits = [cirq.GridQubit(i, j) for i in range(2) for j in range(2)]

# NamedQubit: Qubits with string names
named_qubit = cirq.NamedQubit('my_qubit')

Gates and Operations

Gates represent quantum operations, while operations bind gates to specific qubits:

# Common single-qubit gates
x_gate = cirq.X  # Pauli-X gate (NOT gate)
y_gate = cirq.Y  # Pauli-Y gate
z_gate = cirq.Z  # Pauli-Z gate
h_gate = cirq.H  # Hadamard gate
t_gate = cirq.T  # T gate (π/4 phase rotation)
s_gate = cirq.S  # S gate (π/2 phase rotation)

# Rotational gates
rx = cirq.rx(np.pi/2)  # Rotation around X-axis
ry = cirq.ry(np.pi/2)  # Rotation around Y-axis
rz = cirq.rz(np.pi/2)  # Rotation around Z-axis

# Common two-qubit gates
cnot = cirq.CNOT  # Controlled-NOT gate
cz = cirq.CZ      # Controlled-Z gate
swap = cirq.SWAP  # SWAP gate

# Creating operations (applying gates to qubits)
x_op = cirq.X(q0)  # X gate on qubit q0
h_ops = cirq.H.on_each(line_qubits)  # H gate on each qubit in line_qubits
cnot_op = cirq.CNOT(q0, line_qubits[1])  # CNOT with q0 as control and line_qubits[1] as target

Circuits

Circuits are collections of operations with a specific order:

# Creating an empty circuit
circuit = cirq.Circuit()

# Adding operations to a circuit
circuit.append(cirq.H(q0))
circuit.append(cirq.CNOT(q0, line_qubits[1]))

# Creating a circuit directly from operations
circuit = cirq.Circuit(
    cirq.H(q0),
    cirq.CNOT(q0, line_qubits[1]),
    cirq.measure(q0, key='result')
)

# Creating a circuit with moment structure
circuit = cirq.Circuit(
    # First moment: H gates on all qubits
    cirq.H.on_each(line_qubits),
    
    # Second moment: CNOT gates
    [cirq.CNOT(line_qubits[i], line_qubits[i+1]) for i in range(len(line_qubits)-1)],
    
    # Third moment: Measurements
    cirq.measure(*line_qubits, key='result')
)

Moments

Moments are collections of operations that happen at the same “time”:

# Creating moments
moment1 = cirq.Moment([cirq.H(q) for q in line_qubits])
moment2 = cirq.Moment([cirq.CNOT(line_qubits[0], line_qubits[1])])

# Adding moments to circuit
circuit = cirq.Circuit()
circuit.append(moment1)
circuit.append(moment2)

Measurement

# Single qubit measurement
meas = cirq.measure(q0, key='q0_result')

# Multiple qubit measurement (joint)
meas_multi = cirq.measure(q0, line_qubits[1], key='multi_result')

# Measure all qubits in an iterable
meas_all = cirq.measure(*line_qubits, key='all_results')

Simulating Quantum Circuits

Simulators

# Simulator types
simulator = cirq.Simulator()  # Wavefunction simulator
density_simulator = cirq.DensityMatrixSimulator()  # Density matrix simulator

# Running a circuit
result = simulator.run(circuit)  # Returns measurements
sampled_result = simulator.run(circuit, repetitions=1000)  # Multiple repetitions

# Accessing results
measurements = result.measurements['result']  # Gets the measurement results
histogram = result.histogram(key='result')  # Histogram of measurement results

# Simulating intermediate state (without measurement)
final_state = simulator.simulate(circuit)
print("Final wavefunction:", final_state.final_state_vector)

# Stepping through simulation
step_result = simulator.simulate_moment_steps(circuit)
for i, step in enumerate(step_result):
    print(f"State after step {i}:", step.state_vector())

Noise and Devices

# Adding noise to gates
noisy_x = cirq.AmplitudeDampingChannel(gamma=0.1).on(q0)

# Creating noisy circuit
noisy_circuit = cirq.Circuit()
noisy_circuit.append(cirq.H(q0))
noisy_circuit.append(noisy_x)

# Device specifications
example_device = cirq.google.Sycamore23
device_qubits = example_device.qubit_set()

# Check if circuit can run on device
compiled_circuit = cirq.optimize_for_target_gateset(
    circuit, 
    context=cirq.CompilationContext(deep=True)
)

Quantum Algorithms Implementation

Quantum Fourier Transform

def qft_circuit(qubits):
    """Create a Quantum Fourier Transform circuit on the given qubits."""
    n = len(qubits)
    circuit = cirq.Circuit()
    
    # Apply QFT
    for i in range(n):
        circuit.append(cirq.H(qubits[i]))
        for j in range(i+1, n):
            # Controlled phase rotation
            circuit.append(cirq.CZ(qubits[i], qubits[j])**(1/2**(j-i)))
    
    # Swap qubits to get correct output order
    for i in range(n//2):
        circuit.append(cirq.SWAP(qubits[i], qubits[n-i-1]))
    
    return circuit

Grover’s Algorithm

def grover_circuit(qubits, oracle):
    """Create Grover's algorithm circuit with the given oracle."""
    n = len(qubits)
    circuit = cirq.Circuit()
    
    # Initialize in superposition
    circuit.append(cirq.H.on_each(qubits))
    
    # Number of iterations
    iterations = int(np.floor(np.pi/4 * np.sqrt(2**n)))
    
    for _ in range(iterations):
        # Oracle
        circuit.append(oracle)
        
        # Diffusion operator
        circuit.append(cirq.H.on_each(qubits))
        circuit.append(cirq.X.on_each(qubits))
        circuit.append(cirq.H(qubits[-1]))
        circuit.append(cirq.CNOT(qubits[0], qubits[-1]))
        circuit.append(cirq.H(qubits[-1]))
        circuit.append(cirq.X.on_each(qubits))
        circuit.append(cirq.H.on_each(qubits))
    
    # Measure
    circuit.append(cirq.measure(*qubits, key='result'))
    
    return circuit

Circuit Transformation and Optimization

Circuit Transformers

# Drop empty moments
optimized_circuit = cirq.drop_empty_moments(circuit)

# Merge single qubit gates
optimized_circuit = cirq.merge_single_qubit_gates_into_phased_x_z(circuit)

# Convert to gate set
optimized_circuit = cirq.optimize_for_target_gateset(
    circuit,
    gateset=cirq.CZTargetGateset(),
    context=cirq.CompilationContext(deep=True)
)

# Decompose operations
decomposed_circuit = cirq.Circuit()
for moment in circuit:
    decomposed_moment = cirq.decompose(moment)
    decomposed_circuit.append(decomposed_moment)

Parameterized Circuits

# Create parameters
theta = sympy.Symbol('theta')
phi = sympy.Symbol('phi')

# Parameterized gates
rx_param = cirq.rx(theta)
ry_param = cirq.ry(phi)

# Parameterized circuit
param_circuit = cirq.Circuit(
    rx_param(q0),
    ry_param(q0),
    cirq.measure(q0, key='m')
)

# Resolving parameters with specific values
resolver = cirq.ParamResolver({'theta': np.pi/4, 'phi': np.pi/2})
resolved_circuit = cirq.resolve_parameters(param_circuit, resolver)

# Running parameterized circuit
result = simulator.run(resolved_circuit)

Visualization

# Text diagram of circuit
print(circuit)

# ASCII circuit diagram
print(circuit.to_text_diagram(transpose=True))

# Detailed text diagram with qubit order
print(circuit.to_text_diagram(
    qubit_order=line_qubits,
    transpose=True,
    use_unicode_characters=True
))

# Matplotlib visualization (if cirq-web is installed)
# Note: requires cirq-web package
try:
    import cirq.contrib.svg
    cirq.contrib.svg.SVGCircuit(circuit)
except ImportError:
    print("cirq-web not available for SVG rendering")

Comparison Tables

Common Single-Qubit Gates

GateSymbolMatrix RepresentationDescription
Pauli-XX[[0, 1], [1, 0]]Bit flip (NOT gate)
Pauli-YY[[0, -i], [i, 0]]Bit and phase flip
Pauli-ZZ[[1, 0], [0, -1]]Phase flip
HadamardH1/√2 * [[1, 1], [1, -1]]Creates superposition
SS[[1, 0], [0, i]]π/2 phase rotation
TT[[1, 0], [0, e^(iπ/4)]]π/4 phase rotation
Rx(θ)Rx[[cos(θ/2), -isin(θ/2)], [-isin(θ/2), cos(θ/2)]]Rotation around X-axis
Ry(θ)Ry[[cos(θ/2), -sin(θ/2)], [sin(θ/2), cos(θ/2)]]Rotation around Y-axis
Rz(θ)Rz[[e^(-iθ/2), 0], [0, e^(iθ/2)]]Rotation around Z-axis

Common Two-Qubit Gates

GateSymbolDescriptionCirq Implementation
CNOTCNOTControlled-NOT gatecirq.CNOT(q0, q1)
CZCZControlled-Z gatecirq.CZ(q0, q1)
SWAPSWAPSwaps two qubitscirq.SWAP(q0, q1)
ISWAPISWAPSWAP with additional phasecirq.ISWAP(q0, q1)
CPhaseCPhaseControlled phase rotationcirq.CZ(q0, q1)**phi
XXXXIsing XX interactioncirq.XX(q0, q1)
YYYYIsing YY interactioncirq.YY(q0, q1)
ZZZZIsing ZZ interactioncirq.ZZ(q0, q1)

Common Challenges and Solutions

ChallengeCauseSolution
Circuit doesn’t simulateUnitary operations missingCheck for missing operations in circuit
Unexpected measurement resultsInterference or noiseAdd debugging measurements or simulate step-by-step
Parameter resolution failsParameter not definedVerify all parameters are in the ParamResolver
Circuit too deep for hardwareToo many operationsUse optimization passes to reduce depth
Gate not supported by deviceHardware limitationsUse device-specific gateset and optimize_for_target_gateset
Qubit connectivity issuesHardware topologyUse SWAP networks or routing algorithms
Simulation too slowLarge circuit sizeReduce circuit size or use specialized simulators
Decoherence affecting resultsNoise in simulationAdd noise models or use density matrix simulation

Best Practices and Tips

Code Organization

  • Use functions to create reusable circuit components
  • Separate circuit creation from simulation and analysis
  • Name measurements descriptively (e.g., ‘control_result’ not just ‘m1’)
  • Use consistent qubit naming conventions

Simulation Efficiency

  • Use sparse simulators for large numbers of qubits
  • Avoid unnecessary measurements in intermediate steps
  • Use simulation hooks for custom analysis during simulation
  • Sample multiple repetitions in one simulation run instead of multiple runs

Circuit Design

  • Initialize constants and parameters at the top of your code
  • Comment complex operations or non-standard gates
  • Use circuit optimization functions before running on hardware
  • Decompose custom gates to the target device’s native gate set
  • Consider noise and decoherence when designing circuits for real hardware

Debugging

  • Use moment-by-moment simulation to debug complex circuits
  • Print intermediate states during simulation for verification
  • Visualize circuits to verify structure before running
  • Add assertions to verify expected circuit properties

Resources for Further Learning

Official Documentation and Tutorials

Books and Academic Resources

  • “Quantum Computing: An Applied Approach” by Jack Hidary
  • “Programming Quantum Computers” by O’Reilly Media
  • “Quantum Computation and Quantum Information” by Nielsen and Chuang

Community and Advanced Learning

  • Quantum Computing Stack Exchange
  • Google Quantum AI Research Papers
  • Cirq GitHub Issues for specific problems
  • Qiskit Community (for comparing approaches with other frameworks)

Related Tools and Libraries

  • TensorFlow Quantum (TFQ) for quantum machine learning
  • OpenFermion for quantum chemistry
  • Quantum Virtual Machine (QVM) and Quantum Native Dojo
Scroll to Top