# unexpected effect of coherent unitary error in qiskit

I'm trying to simulate the effect of a coherent unitary Z rotation at an arbitrary angle of a single qubit on the fidelity of a quantum circuit. I am using the qiskit Aer noisy simulator. More specifically, my goal is to quantify the loss of fidelity associated with the fact that when attempting to apply any gate with a unitary $$U$$, I apply instead the gate

$$V = R_{i,z}^\dagger(\epsilon)UR_{i,z}(\epsilon)$$

where $$i$$ is an index of a single qubit.

As a sanity check, I am trying the single qubit case first, where I expect this error to not have any effect, since the initial state of the qubit is $$|0\rangle$$ and the measurement is in the Z basis. Thus, assuming that the coherent unitary channel acts on the state as $$\mathcal{E}(\rho) = U\rho U^\dagger$$, this error should get absorbed into the preperation and measurement and not have any effect on the fidelity.

When I simulate this circuit however, I find that the fidelity does go below 1 as I increase the error. It seems like the qiskit method coherent_unitary_error function from qiskit does not return a QuantumError object which has the effect of applying $$\mathcal{E}(\rho)$$ as defined above. Does that make sense?

I am including here a self-contained code sample which shows this behavior. One easy way to trigger this effect on and off is to change the optimization_level parameter in line 21 of the attached code. If it is 0, then the two Hadamards don't get merged into one and we see an error. If it is 1 or larger, they get merged and no error appears. Of course, manually adding the Z rotations to the circuit does not lead to an error.

Any ideas? Did I misunderstand how the noise model works, or is there a more fundamental issue here?

import qiskit
from qiskit import QuantumCircuit, transpile
from qiskit.providers.aer import AerSimulator
from qiskit.providers.aer.noise import NoiseModel, coherent_unitary_error

epsilon = 0.1
z_rot = qiskit.circuit.library.U1Gate(epsilon)
z_rot_dg = qiskit.circuit.library.U1Gate(-epsilon)

noise_model = NoiseModel()
print(noise_model)
noise_sim = AerSimulator(noise_model=noise_model)

circ = QuantumCircuit(1, 1)
circ.h(0)
circ.h(0)
circ.measure(0, 0)

# change optimization level to 1 to turn off effect of channel
ct = transpile(circ, noise_sim, optimization_level=0)
print(ct.draw())
nshots=10000
job = noise_sim.run(ct, shots=nshots)
print(job.result().get_counts()['0']/nshots)
$$$$

• The hadamards prepare the superpostion state $(|0\rangle + |1\rangle)/\sqrt{2}$, which is sensitive to $Z$ rotation error. Aug 8 at 22:57
• that's correct, but if I apply two Hadamards in a row as I did here, I expect to see only 1's in my measurement. This would be true for any kind of benchmark or characterization sequence, even when performing a single Hadamard. Also, the result shouldn't depend on the optimization level of the transpiler
– Lior
Aug 8 at 23:01

I think I understand the issue - I incorrectly assumed that the error operator is applied to the unitary and not to the state. Once I use the definition from the link above I get the correct result, here's an example:

import qiskit
from qiskit import QuantumCircuit, transpile
from qiskit.providers.aer import AerSimulator
from qiskit.providers.aer.noise import NoiseModel, coherent_unitary_error
import qiskit.quantum_info as qi
from qiskit.visualization import array_to_latex

epsilon = 0.1

err_h = QuantumCircuit(1, 1)
err_h.h(0)
err_h.p(epsilon, 0)
err_h.h(0)
err_h.p(-epsilon, 0)

u_err_h = qi.Operator(err_h)

noise_model = NoiseModel()
`