Qiskit / qiskit-aer

Aer is a high performance simulator for quantum circuits that includes noise models
https://qiskit.github.io/qiskit-aer/
Apache License 2.0
480 stars 357 forks source link

QuantumError.compose sometimes returns incorrect results #580

Closed lucacrippa88 closed 4 years ago

lucacrippa88 commented 4 years ago

Informations

What is the current behavior?

When building a custom noise_model combining Qiskit Aer depolarization_error and thermal_relaxation_error in simulating final state density matrix after a Rx(pi*0.3) rotation, I obtain real part and imaginary part of density matrix that are opposite to density matrix calculated with Qiskit Ignis Tomography function. I.e.: element rho_real_00 is inverted with rho_real_11.

Steps to reproduce the problem

Calculate density matrix of a Rx(pi*3) with Qiskit Ignis Tomography function. Plot real and imaginary part of density matrix. Reproduce the same density matrix calculation with Aer imposing depolarization_error and thermal_relaxation_error.

What is the expected behavior?

The expected behaviour is that the two calculated density matrices should be close each other. Another expected behaviour is that by reducing the depolarization error near to zero, the two matrices should be close each other. The two density matrices are close each other only if one of the two depolarization or thermal_relaxation errors are set to zero (or deleted from noise model).

Suggested solutions

Check error combination logic.

nonhermitian commented 4 years ago

Can you please move this issue to the Qiskit Aer repository. They can better address it there.

chriseclectic commented 4 years ago

I don't quite understand the setup you are describing. Are you saying you:

  1. Make a circuit with a single Rx gate
  2. Execute with a noise model on Aer to run state tomography from ignis
  3. Execute with a noise model on Aer and take final state density matrix snapshot.

And 2 and 3 are producing different density matrices? Can you post a code example?

lucacrippa88 commented 4 years ago

Hi, let me recap and share the code.

A single Rx(theta) is considered (written in terms of U3).

Calculation of density matrix on real HW with Ignis Tomography -> affected by HW errors Calculation of theoric (using vectors and matrices math calculations) density matrix = |psi_final><psi_final| -> exact Calculation of density matrix on Aer simulator with HW errors readout_error, depolarization_error, thermal_relaxation_error For the Aer errors parametrizations, I followed this tutorial: https://quantum-computing.ibm.com/jupyter/tutorial/advanced/aer/3_building_noise_models.ipynb

and I used T1 and T2 listed on chip calibration.

Expected behaviour: density matrix 1 similar to density matrix 3, some differences with density matrix 2 (because it is exact, without errors). Found behaviour: when enabling both thermal and depolariz errors, Real and Imaginary part of density matrix are inverted respect to theoric calculation and real HW Ignis Tomography results. You can change Aer errors enabled in "Density matrix Aer noisy simulation with generalized U(eps)" cell, on lines:

TRY SETTING 1-0 OR 0-1

thermal = 1 depolariz = 0

Code (Jupyter Notebook): https://ibm.box.com/s/5wu1lb76z1ernekqz7b6po70heb3vqm6

chriseclectic commented 4 years ago

Thanks for the example notebook. I can't see anything obviously incorrect there, so there may indeed be a bug in the QuantumError.compose function. I'll look into it.

I did notice that if the part of your code that had depol_err.compose(err_u3[j]) was replaced by Kraus(depol_err).compose(err_u3[j]) the bug seemed to disappear.

chriseclectic commented 4 years ago

Here is a more minimal example of the bug:

from qiskit.quantum_info import SuperOp
from qiskit.providers.aer.noise import depolarizing_error, thermal_relaxation_error

depol = depolarizing_error(0.001, 1)
kraus = thermal_relaxation_error(50e3, 100e3, 100)

target = SuperOp(depol).compose(SuperOp(kraus))
actual = SuperOp(depol.compose(kraus))

print('Target:\n', target.data.round(3))
print('Actual:\n', actual.data.round(3))
Target:
 [[1.   +0.j 0.   +0.j 0.   +0.j 0.002+0.j]
 [0.   +0.j 0.998+0.j 0.   +0.j 0.   +0.j]
 [0.   +0.j 0.   +0.j 0.998+0.j 0.   +0.j]
 [0.   +0.j 0.   +0.j 0.   +0.j 0.998+0.j]]
Actual:
 [[ 0.002+0.j  0.   +0.j  0.   +0.j  1.   +0.j]
 [ 0.   +0.j -0.   +0.j  0.999+0.j  0.   +0.j]
 [ 0.   +0.j  0.999+0.j -0.   +0.j  0.   +0.j]
 [ 0.998+0.j  0.   +0.j  0.   +0.j  0.   +0.j]]