I would like to know some circuit decomposition for an arbitrary controlled Pauli string rotation: \begin{equation} |0\rangle\langle 0| \otimes e^{i \theta (P_1\otimes...\otimes P_n)}+ |1\rangle\langle 1| \otimes I \end{equation} where $P_i$ are Pauli operators. What's a simple circuit decomposition for that?
2 Answers
This is nearly a built-in decomposition in cirq. Here's what happens when you decompose a Pauli product:
import cirq
a, b, c, d, e = cirq.LineQubit.range(5)
product = cirq.X(a) * cirq.X(b) * cirq.Y(c) * cirq.Y(d) * cirq.Z(e)
power = product**0.125
ops = cirq.decompose_once(power)
print(cirq.Circuit(ops).to_text_diagram(use_unicode_characters=False))
Which prints:
0: ---Y^-0.5---X---X---X---X---Z^(1/8)---X---X---X--------X--------Y^0.5---
| | | | | | | |
1: ---Y^-0.5---@---|---|---|-------------|---|---|--------@--------Y^0.5---
| | | | | |
2: ---X^0.5--------@---|---|-------------|---|---@--------X^-0.5-----------
| | | |
3: ---X^0.5------------@---|-------------|---@---X^-0.5--------------------
| |
4: ---I--------------------@-------------@---I-----------------------------
It works by conjugating the Pauli product by single qubit gates to turn it into a product of Z observables, then conjugating by CNOTs to reduce that to a single Z observable, then phasing that single observable.
Anyways, the point is that the key operation in this entire thing is that one Z gate in the middle. Everything else is self-undoing conjugation. So...
C: ----------------------------@-------------------------------------------
|
0: ---Y^-0.5---X---X---X---X---Z^(1/8)---X---X---X--------X--------Y^0.5---
| | | | | | | |
1: ---Y^-0.5---@---|---|---|-------------|---|---|--------@--------Y^0.5---
| | | | | |
2: ---X^0.5--------@---|---|-------------|---|---@--------X^-0.5-----------
| | | |
3: ---X^0.5------------@---|-------------|---@---X^-0.5--------------------
| |
4: ---I--------------------@-------------@---I-----------------------------
Controlling that one key gate controls the entire operation.
This decomposition is now built into pytket.
As pointed out by the accepted answer, you can make a controlled Pauli string rotation (aka a controlled Pauli gadget) by only controlling on the central $Z$ rotation. This is way more efficent in terms of circuit complexity than naively controlling on the other operations.
Here's an example for $\theta=0.7$ and with the Pauli string $ Z \otimes Z \otimes Y \otimes X$.
More generally, there's a simple pattern for when you can do this. If the base gate $U$ in your controlled gate is of the form
$$ \begin{equation} U = V \, A \, V^\dagger, \end{equation} $$
then it is sufficent to only control on the central $A$ operation. You can see that the above circuit fits this conjugation pattern. I wrote a short blog post on this.
Here's the pytket code to generate the controlled Pauli operation shown above.
from pytket.pauli import Pauli
from pytket.circuit import PauliExpBox, QControlBox
zzyx_box = PauliExpBox([Pauli.Z, Pauli.Z, Pauli.Y, Pauli.X], 0.7)
# Controlled Pauli gadget with a single control.
controlled_pauli = QControlBox(zzyx_box, 1)