mitiq
mitiq copied to clipboard
PT+ ZNE Tutorial and Pauli Transfer Matrix (PTM) in Cirq
Add tutorial combining ZNE with PT and show this via PTM.
To show that pauli twirling has worked and the noise has been tailored, PTM superoperator could be used.
If twirling is done perfectly, the off-diagonal terms in this superoperator should be suppressed. An example of this is in Sec VII of the supplemental material of https://arxiv.org/abs/2010.00215
before:
after:
This superoperator is defined in Qiskit : https://qiskit.org/documentation/stubs/qiskit.quantum_info.PTM.html
Use PTM in cirq to show execute_with_pauli_twirling
has worked as expected.
I have got a crude working code for finding the PTM matrix in the first screenshot of this issue's description. It depends on the channel superoperator acting on a vectorized form of Pauli matrices.
I think an easier method (compared to what's implemented below ) would be to change the basis of the superoperator to a Pauli basis. Need to plan the implementation of this as it will be easy to generalize to cases where the circuit has >1 qubits.
Plus, Mitiq's twirling method only works for twirling the noise on CNOT and CZ gates.
Imports
import cirq
import numpy as np
Defining functions to vectorize a matrix & to get a matrix from a vectorized form
def matrix_vec(matrix):
"""Defines the vectorized form of a numpy array."""
matrix_transpose = np.transpose(matrix)
return(np.reshape(matrix_transpose, (-1,1)))
def matrix_no_vec(vec_matrix):
"""Defines the matrix form of a vectorized state."""
vec_to_matrix = np.reshape(vec_matrix, (2,2))
return(np.transpose(vec_to_matrix))
Create a vectorized list of paulis
pauli_list = [cirq.unitary((cirq.I)), cirq.unitary((cirq.X)), cirq.unitary((cirq.Y)), cirq.unitary((cirq.Z))]
pauli_vec_list = []
for i in range(len(pauli_list)):
pauli_vec_list.append(matrix_vec(pauli_list[i]))
Defining the PTM matrix function
def ptm_matrix(circuit):
superop = cirq.kraus_to_superoperator(cirq.kraus(circuit))
ptm_matrix = np.zeros([4,4],dtype=complex)
for i in range(len(pauli_vec_list)):
superop_on_pauli_vec = np.matmul(superop, pauli_vec_list[i])
superop_on_pauli_matrix = matrix_no_vec(superop_on_pauli_vec)
ptm_matrix_row = []
for j in range(len(pauli_list)):
pauli_superop_pauli = np.matmul(pauli_list[j], superop_on_pauli_matrix)
ptm_matrix_row.append(0.5*np.trace(pauli_superop_pauli))
ptm_matrix[i] = ptm_matrix_row
return(ptm_matrix)
Testing the PTM function
q0= cirq.LineQubit(0)
circuit = cirq.Circuit()
circuit.append(cirq.Rz(rads=0.25 * np.pi)(q0))
ptm_matrix(circuit)
array([[ 1.00000000e+00+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 5.55111512e-17+0.j],
[ 0.00000000e+00+0.j, 7.07106781e-01+0.j, -7.07106781e-01+0.j, 0.00000000e+00+0.j],
[ 0.00000000e+00+0.j, 7.07106781e-01+0.j, 7.07106781e-01+0.j, 0.00000000e+00+0.j],
[ 5.55111512e-17+0.j, 0.00000000e+00+0.j, 0.00000000e+00+0.j, 1.00000000e+00+0.j]])
@Misty-W Using a PTM matrix to show the off-diagonal terms are zero after twirling would work when CNOT/CZ are the only gates contributing to the off-diagonal terms in the PTM matrix.
My example is for a Z-rotation. The off-diagonal terms will not go away after Pauli twirling if my circuit consisted of Rz and CNOT as Mitiq's method only works for CZ and CNOT gates.
Option 1: Use a PTM matrix to show that Pauli twirling has tailored the noise. If the off-diagonal terms are non-zero, then we should at least expect these to decrease after Pauli twirling.
Option 2: Allow twirling of other single-qubit gates. In this case, using the PTM matrix would be straightforward even if the circuit is a mix of single/two-qubit gates.
hi @purva-thakre, sorry for the delayed response. Was finalizing conference submissions etc. last week.
I prefer Option 1 for now, we can expand to Option 2 when we extend the technique.
@Misty-W No worries.
Will this be a function defined in the tests folder? Or a separate function verify_pt_tailored_noise
in mitiq/pt/pt.py ?
Will this be a function defined in the tests folder? Or a separate function
verify_pt_tailored_noise
in mitiq/pt/pt.py ?
Hmmm, my first inclination is to put it in the tests, but is there another use you have in mind for this function as a sort of PT utility?
is there another use you have in mind for this function as a sort of PT utility?
If we want to demonstrate Pauli Twirling worked as expected in a tutorial or an example, use the function to compare the off-diagonal matrix entries before and after.
is there another use you have in mind for this function as a sort of PT utility?
If we want to demonstrate Pauli Twirling worked as expected in a tutorial or an example, use the function to compare the off-diagonal matrix entries before and after.
Got it! Let's make it a function in mitiq.pt/pt.py.
An interesting way to interpret the Pauli Twirling Matrix visually (before & after the noise is tailored by Pauli Twirling for the entire circuit):
Screenshot taken from this talk.
hi @purva-thakre, wanted to check if this issue will be completely solved by #1987, or only partially. If only partially, I'd suggest to move this issue out of the milestone.
Superseded by #2374
@purva-thakre apologies, I hadn't realised this was opened already. Happy to close #2374, since this has more context.
@cosenal No worries! Sounds like you are close to completing the other issue anyway.
I wouldn't have gotten to making a PR for this until #2346 was successfully merged.