Pauli Propagation Backend
Simulating noisy quantum circuits efficiently is a crucial challenge in quantum computing. The Pauli Propagation method[Rudolph2025] provides an efficient way to simulate circuits under certain noise models by tracking how Pauli observables evolve through the circuit. The PauliPropagation extension in Yao provides a convenient interface to convert Yao circuits into the Pauli propagation framework.
Overview
Pauli propagation represents quantum circuit simulation as the evolution of Pauli strings through gates and noise channels. This approach offers several advantages:
- Efficiency: Scales polynomially for certain circuit classes, especially with sparse Pauli evolution
- Noise Support: Natural representation of common noise models (depolarizing, Pauli channels)
- Observable-Centric: Directly computes expectation values without full state vector
The method works by propagating a Pauli observable backwards through the circuit, keeping track of how the observable transforms under gates and noise.
Installation
The PauliPropagation extension is automatically loaded when you have both packages:
using Yao
using PauliPropagationBasic Usage
Converting Circuits to PauliPropagation
The primary function for circuit conversion is:
yao2paulipropagation(circuit; observable)This function transforms a Yao circuit into a PauliPropagationCircuit intermediate representation.
Parameters:
circuit::ChainBlock: The quantum circuit to convert. Must contain only gates supported by PauliPropagation (Clifford gates, rotations, and noise channels)observable: A Yao block specifying the observable to measure. Must be a sum of Pauli strings
Returns:
PauliPropagationCircuit: An intermediate representation containing the circuit gates and observable as aPauliSum
Propagating Observables
Once you have a PauliPropagationCircuit, propagate the observable through the circuit:
propagate(pc; kwargs...)Returns:
PauliSum: The propagated observable. Useoverlapwithzero(psum)to get the expectation value
Example
Here's a complete example showing how to simulate a noisy quantum circuit:
using Yao, PauliPropagation
# Create a noisy circuit with rotation gates and depolarizing noise
n = 5
circuit = chain(n,
put(n, 1=>H),
put(n, 2=>Rx(0.3)),
control(n, 1, 2=>X),
put(n, 1=>quantum_channel(DepolarizingError(1, 0.01)))
)
# Define an observable (e.g., measure Z on first qubit)
observable = put(n, 1=>Z)
# Convert to PauliPropagation representation
pc = yao2paulipropagation(circuit; observable=observable)
# Propagate the observable through the circuit
psum = propagate(pc)
# Get the expectation value
exp_pauli = real(overlapwithzero(psum))
println("PauliPropagation result: ", exp_pauli)
# Compare with exact density matrix simulation
reg = zero_state(n) |> density_matrix
reg_final = apply!(reg, circuit)
exp_exact = real(expect(observable, reg_final))
println("Exact simulation result: ", exp_exact)
println("Difference: ", abs(exp_pauli - exp_exact))PauliPropagation result: 0.0
Exact simulation result: 0.0
Difference: 0.0The observable can also be a sum of Pauli strings (e.g., a Hamiltonian):
# Multi-term observable
hamiltonian = put(n, 1=>X) + 2.0 * kron(n, 1=>Z, 2=>Z)
pc2 = yao2paulipropagation(circuit; observable=hamiltonian)
exp_val = real(overlapwithzero(propagate(pc2)))
println("Hamiltonian expectation: ", exp_val)Hamiltonian expectation: 1.8915662484687Supported Gates and Channels
Clifford Gates
- Pauli gates:
X,Y,Z - Hadamard:
H - Phase gates:
S,T,Sdag,Tdag - Two-qubit gates:
control(n, ctrl, target=>X)(CNOT),control(n, ctrl, target=>Z)(CZ),SWAP,Toffoli
Rotation Gates
Rx(θ),Ry(θ),Rz(θ)and their multi-qubit versions
Noise Channels
DepolarizingChannel: Depolarizing noiseMixedUnitaryChannel: Pauli noise channels (X, Y, Z errors)AmplitudeDampingError: Amplitude damping
API Reference
YaoBlocks.yao2paulipropagation — Functionyao2paulipropagation(circ::ChainBlock; observable)Convert a Yao circuit to a Pauli propagation circuit representation. You must using PauliPropagation before using this function.
Arguments
circ::ChainBlock: Yao circuit in the form of a chain of basic gates.
Keyword Arguments
observable: A Yao block specifying the observable to measure (required). Must be a sum of Pauli strings, e.g.kron(5, 2=>X, 3=>X) + 2.0 * kron(5, 1=>Z). Will be converted to aPauliSum.
Returns
PauliPropagationCircuit: An intermediate representation that can be evaluated withpropagate(pc).
YaoBlocks.paulipropagation2yao — Functionpaulipropagation2yao(n::Int, circ::AbstractVector{Gate}, thetas::AbstractVector)
paulipropagation2yao(pc::PauliCircuit)Convert a Pauli propagation circuit to a Yao circuit. You must using PauliPropagation before using this function.
Arguments
n::Int: Number of qubits.circ::AbstractVector{Gate}: Pauli propagation circuit.thetas::AbstractVector: Vector of parameters.
Or:
pc::PauliCircuit: A PauliCircuit intermediate representation.
PauliPropagationCircuit
An intermediate representation that holds a circuit and observable in PauliPropagation format.
Fields:
n::Int: Number of qubitsgates::Vector{StaticGate}: Vector of frozen gatesobservable::PauliSum: Observable as a sum of Pauli strings
propagate(pc::PauliPropagationCircuit; kwargs...)
Propagate the observable through the circuit.
Keyword Arguments:
max_weight: Maximum Pauli weight to keep (default: no limit)min_abs_coeff: Minimum coefficient magnitude to keep (default: 0)
Returns: PauliSum - the propagated observable
Performance Tips
- Truncation: Use
max_weightandmin_abs_coeffto control the size of the Pauli sum during propagation - Observable Choice: Simpler observables (lower Pauli weight) propagate more efficiently
- Circuit Structure: Circuits with limited entanglement spread maintain sparse Pauli sums
- Frozen Rotations: All rotation parameters are frozen into the gates for efficient propagation
References
- Rudolph2025Rudolph, Manuel S., Jones, Tyson, Teng, Yanting, Angrisani, Armando, and Holmes, Zoe. "Pauli Propagation: A Computational Framework for Simulating Quantum Systems." arXiv:2505.21606 (2025). https://arxiv.org/abs/2505.21606