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
483 stars 358 forks source link

CNOT gate noise does not scale as expected when simulating device noise #600

Closed andrehche closed 4 years ago

andrehche commented 4 years ago

Informations

What is the current behavior?

For a simple test circuit with only one CNOT gate (setting n=0), the results from the code snippet below are as expected: similar to {'01': 9, '10': 20, '00': 995} (mostly '00' with device noise causing population in other states). If we insert n additional pairs of CNOT gates, we expect the measured result to approach some noisy limit, since pairs of CNOT gates cancel each other but increase the noise in the circuit. However, what I find is that even for extremely high values of n, such as 1000 (2001 CNOT gates in the circuit!), the measured values are virtually the same as the original circuit with only one CNOT with what seems like no increase in the effect of noise. I have set optimization_level=0 to ensure that the additional CNOT gates are not optimized away.

Steps to reproduce the problem

from qiskit import QuantumCircuit, execute
from qiskit import Aer, IBMQ
from qiskit.providers.aer.noise import NoiseModel

# Choose a real device to simulate from IBMQ provider
provider = IBMQ.load_account()
backend = provider.get_backend('ibmq_vigo')
coupling_map = backend.configuration().coupling_map

# Generate an Aer noise model for device
noise_model = NoiseModel.from_backend(backend)
basis_gates = noise_model.basis_gates

# Generate a quantum circuit
qc = QuantumCircuit(2, 2)

n = 1000
qc.cx(0, 1)
for n in range(n): 
    qc.cx(0, 1)
    qc.cx(0, 1)
qc.measure([0, 1], [0, 1])

# Perform noisy simulation
backend = Aer.get_backend('qasm_simulator')
job = execute(qc, backend,
              coupling_map=coupling_map,
              noise_model=noise_model,
              basis_gates=basis_gates, 
              optimization_level=0)
result = job.result()

print(result.get_counts(0))

Results for up to 50 extra CNOT pairs:

{0: {'01': 12, '10': 13, '00': 999},
 1: {'01': 8, '10': 13, '00': 1003},
 2: {'01': 4, '10': 20, '11': 2, '00': 998},
 3: {'01': 7, '10': 15, '00': 1002},
 4: {'01': 10, '10': 19, '00': 995},
 5: {'01': 7, '10': 14, '00': 1003},
 6: {'01': 6, '10': 18, '00': 1000},
 7: {'01': 8, '10': 21, '00': 995},
 8: {'01': 7, '10': 15, '00': 1002},
 9: {'01': 9, '10': 16, '00': 999},
 10: {'01': 6, '10': 19, '00': 999},
 11: {'01': 4, '10': 16, '00': 1004},
 12: {'01': 8, '10': 22, '00': 994},
 13: {'01': 10, '10': 14, '11': 1, '00': 999},
 14: {'01': 7, '10': 18, '00': 999},
 15: {'01': 8, '10': 14, '00': 1002},
 16: {'01': 7, '10': 9, '00': 1008},
 17: {'01': 13, '10': 15, '00': 996},
 18: {'01': 8, '10': 25, '00': 991},
 19: {'01': 3, '10': 23, '00': 998},
 20: {'01': 1, '10': 20, '00': 1003},
 21: {'01': 3, '10': 19, '00': 1002},
 22: {'01': 8, '10': 15, '00': 1001},
 23: {'01': 6, '10': 20, '00': 998},
 24: {'01': 7, '10': 19, '00': 998},
 25: {'01': 15, '10': 13, '00': 996},
 26: {'01': 5, '10': 16, '00': 1003},
 27: {'01': 8, '10': 16, '00': 1000},
 28: {'01': 7, '10': 17, '00': 1000},
 29: {'01': 5, '10': 28, '00': 991},
 30: {'01': 6, '10': 12, '00': 1006},
 31: {'01': 2, '10': 16, '11': 1, '00': 1005},
 32: {'01': 10, '10': 21, '11': 2, '00': 991},
 33: {'01': 3, '10': 25, '00': 996},
 34: {'01': 11, '10': 14, '00': 999},
 35: {'01': 14, '10': 24, '00': 986},
 36: {'01': 2, '10': 21, '00': 1001},
 37: {'01': 10, '10': 20, '00': 994},
 38: {'01': 9, '10': 21, '11': 1, '00': 993},
 39: {'01': 5, '10': 24, '00': 995},
 40: {'01': 7, '10': 14, '00': 1003},
 41: {'01': 9, '10': 21, '00': 994},
 42: {'01': 5, '10': 21, '00': 998},
 43: {'01': 10, '10': 19, '00': 995},
 44: {'01': 3, '10': 18, '00': 1003},
 45: {'01': 8, '10': 18, '00': 998},
 46: {'01': 7, '10': 24, '00': 993},
 47: {'01': 4, '10': 15, '00': 1005},
 48: {'01': 9, '10': 22, '00': 993},
 49: {'01': 2, '10': 18, '00': 1004}}

What is the expected behavior?

If we insert n additional pairs of CNOT gates, we expect the measured result to approach some noisy limit (like measuring a completely mixed state), since pairs of CNOT gates cancel each other to form the identity but increase the amount of noise in the circuit.

Suggested solutions

chriseclectic commented 4 years ago

This doesn't look like a bug, just a bad choice of initial state for this test circuit: A CNOT gate applied to the ground state has no effect. Depolarizing error will occasionally perform a bit flip of one or both qubits, and thermal relaxation will send them back to zero, which is what you are seeing.

If you want to see error accumulating you would need a different initial state. Eg apply a hadamard to qubit 0 and then it very quickly results in a highly mixed state with additional CNOTs, but if you run it long enough you will see the effect of relaxation biasing towards 00 again:

nqs = list(range(5)) + list(range(10, 110, 10))
for n in nqs:
    qc.h(0)
    qc.cx(0, 1)
    for _ in range(n): 
        qc.cx(0, 1)
        qc.cx(0, 1)
    qc.measure([0, 1], [0, 1])

    # Perform noisy simulation
    sim = Aer.get_backend('qasm_simulator')
    job = execute(qc, sim,
                  coupling_map=coupling_map,
                  noise_model=noise_model,
                  basis_gates=basis_gates, 
                  optimization_level=0)
    result = job.result()
    print('N={}'.format(n), result.get_counts(0))

Results in

N=0 {'10': 20, '11': 478, '01': 21, '00': 505}
N=1 {'10': 265, '11': 254, '01': 247, '00': 258}
N=2 {'10': 247, '11': 254, '01': 252, '00': 271}
N=3 {'10': 256, '11': 229, '01': 246, '00': 293}
N=4 {'10': 246, '11': 284, '01': 235, '00': 259}
N=10 {'10': 246, '11': 255, '01': 220, '00': 303}
N=20 {'10': 244, '11': 200, '01': 230, '00': 350}
N=30 {'10': 232, '11': 226, '01': 195, '00': 371}
N=40 {'10': 225, '11': 214, '01': 166, '00': 419}
N=50 {'10': 182, '11': 196, '01': 187, '00': 459}
N=60 {'10': 200, '11': 188, '01': 148, '00': 488}
N=70 {'10': 187, '11': 178, '01': 151, '00': 508}
N=80 {'10': 178, '11': 162, '01': 129, '00': 555}
N=90 {'10': 160, '11': 178, '01': 120, '00': 566}
N=100 {'10': 165, '11': 127, '01': 113, '00': 619}
chriseclectic commented 4 years ago

Closing this issue as it appears to be resolved.