Second-Order Twirl & Quadratic Symmetries¶
This page details the computation of the second-order Pauli twirl, a key operation in quantum information theory for characterizing noise and benchmarking quantum devices. The calculation relies on the concept of “quadratic symmetries” of the underlying gate set.
Theoretical Background¶
The second-order twirl of a quantum channel or operator \(M\) over a group \(G\) is given by its projection onto the commutant of the twofold tensor product representation of the group, \(U^{\otimes 2}\).
Supplemental Theorem 1 of arXiv:2310.11505 provides a powerful way to compute this by constructing an orthogonal basis for this space, called the quadratic symmetries, \(Q_{kj}\).
Definitions:
Linear Symmetries (:math:`L_j`): The set of Pauli strings that commute with all generators of the system \(G\). This is found using
system.get_commutants()
.Commutator Graph Components (:math:`C_k`): The connected components of the graph of all Pauli strings, where edges are defined by commutation with the generators of \(G\). This is found using the internal
system.get_commutator_graph_components()
method.
The quadratic symmetries are then constructed as:
The final second-moment twirl of an operator \(M\) is its projection onto this basis:
PauLie
provides the second_moment
application function to perform this entire calculation.
Usage Example¶
The main user-facing function is second_moment
, which takes a system definition and an operator to twirl. Let’s use a simple system generated by the Pauli-Z operator and see how it affects the operator \(X \otimes I\).
from paulie.common.pauli_string_factory import get_pauli_string as p
from paulie.application.second_moment import second_moment
# Define the system generators (a group generated by Z on 1 qubit)
system = p(["Z"])
# Define an operator M to twirl.
# Note: M must be a 2n-qubit operator. Since our system is n=1, M is 2-qubit.
M = p([(1.0, "XI")])
# Compute the second-order twirl. The function handles the construction
# of the quadratic symmetry basis internally.
twirled_M = second_moment(M, system)
print(f"Original operator M: {M}")
print(f"Twirled operator T^(2)(M): {twirled_M}")
Output:
Original operator M: XI
Twirled operator T^(2)(M): 0.0*II
In this case, the result is the zero operator because the operator \(X \otimes I\) has no overlap with any of the quadratic symmetries generated by the Z-group. The second_moment
function correctly projects it to zero.