Pauli evolution gate

The Pauli evolution gate, exp(−itH) for a Pauli-sum Hamiltonian: parameters, the PauliEvolutionGate call in Python and JS, and how IonQ receives it.

The Pauli evolution gate applies eitHe^{-itH} to a set of qubits, where HH is a Hamiltonian written as a weighted sum of Pauli strings and tt is a time. It is how a circuit simulates a physical system evolving under HH, and the building block of Trotterised time evolution and QAOA layers. It acts on as many qubits as the Pauli strings are long and takes two parameters: the operator and the time. The Circuit panel draws it as exp(…)(t), with the weighted terms inside the brackets and the time after them. Run on fresh qubits, the example below leaves every shot reading 00: with these terms the gate only adds phases, which show once other gates put the qubits in superposition.

Kets such as 0\vert 0 \rangle name the basis states and rotations are described on the Bloch sphere; the qubits lesson introduces both.

Call

WhereCall
Pythonqc.append(PauliEvolutionGate(operator, time=t), qubits)
JScircuit.append(PauliEvolutionGate.callKwargs(operator, { time: t }), qubits)
Qiskit classPauliEvolutionGate, from qiskit.circuit.library

operator is a SparsePauliOp from qiskit.quantum_info: a list of Pauli strings and a list of coefficients. In JS, keyword arguments go through .callKwargs, so the constructor call is PauliEvolutionGate.callKwargs(operator, { time: t }); see JS / Qiskit projects.

Backend requirements

The built-in simulator and the IBM noise models do not take the gate as written: run transpile(qc, backend) first and Qiskit unrolls it into the backend's own gates. IonQ backends take it as submitted when its terms all commute with each other; terms that do not commute need IonQ's compiler synthesis, backend.set_options(extra_metadata={"ionq_compiler_synthesis": True}), or the run stops before submission with IonQPauliExponentialError. Details under On the simulators and On IonQ hardware.

What it computes

U(t)=eitH,H=kckPkU(t) = e^{-itH}, \qquad H = \sum_k c_k P_k

Each PkP_k is a Pauli string such as ZZ or XI and each ckc_k its real coefficient. Two single-term cases fix the scale: exp(−itZ) on one qubit is an RZ gate of angle 2t2t, and exp(−itZZ) on two qubits is an RZZ gate of angle 2t2t. The letter I in a string means the gate leaves that qubit alone.

Qiskit synthesises the gate with a product formula, Lie-Trotter by default, which is exact when every term commutes with every other and an approximation otherwise. The approximation improves with more Trotter steps, at the cost of more gates.

Inverse

The inverse of evolution for time tt is evolution for time t-t.

Usage

from qiskit import QuantumCircuit
from qiskit.circuit.library import PauliEvolutionGate
from qiskit.quantum_info import SparsePauliOp

H = SparsePauliOp(["ZZ", "ZI", "IZ"], [1.0, 0.5, 0.5])

qc = QuantumCircuit(2, 2)
qc.append(PauliEvolutionGate(H, time=0.3), [0, 1])
qc.measure([0, 1], [0, 1])
import { QuantumCircuit } from 'qiskit';
import { PauliEvolutionGate } from 'qiskit.circuit.library';
import { SparsePauliOp } from 'qiskit.quantum_info';

const H = SparsePauliOp(['ZZ', 'ZI', 'IZ'], [1.0, 0.5, 0.5]);

const circuit = QuantumCircuit(2, 2);
circuit.append(PauliEvolutionGate.callKwargs(H, { time: 0.3 }), [0, 1]);
circuit.measure([0, 1], [0, 1]);

The Circuit panel shows this as exp(ZZ + 0.5ZI + 0.5IZ)(0.3).

On the simulators

The built-in simulator and the IBM noise models do not take the gate as written: run transpile(qc, backend) first and Qiskit unrolls it into the backend's own gates, rzz and rz on the built-in simulator and cz, sx and rz on an IBM noise model for the example above. See Transpilation.

On IonQ hardware

Qollab submits the gate to IonQ as a single pauliexp operation carrying the Pauli strings, their coefficients and the time, rather than as Qiskit's synthesised gate sequence, and IonQ's compiler chooses the decomposition on its side. That path takes terms that all commute with each other, as in the example above. Terms that do not commute are refused before submission with IonQPauliExponentialError unless you opt in to IonQ's compiler synthesis first:

backend.set_options(extra_metadata={"ionq_compiler_synthesis": True})

With the option set, IonQ decomposes the non-commuting sum on its side as well. See How your circuit is compiled.

Stay in the loop.

Get the latest tutorials, demos, and project showcases straight to your inbox. No noise, just the good stuff.