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 354 forks source link

Improve interface of delay gates with thermal noise #1440

Closed yaelbh closed 2 years ago

yaelbh commented 2 years ago

What is the expected behavior?

Recent work in Aer has introduced the ability to simulate thermal noise in delay gates, such that the delay time affects the amount of noise. This is how the interface looks like (these lines are taken from the T1 tutorial in qiskit-experiments):

# Create a pure relaxation noise model for AerSimulator
noise_model = NoiseModel.from_backend(
    FakeVigo(), thermal_relaxation=True, gate_error=False, readout_error=False
)

# Set your desired t1 and t2
< I don't know how to do it, but I guess I could find out >

# Create a fake backend simulator
backend = AerSimulator.from_backend(FakeVigo(), noise_model=noise_model)

I'd expect a much simpler interface, where all one has to do is to build a noise model with specified T1 and T2. The current interface forces the user to apply three steps:

  1. Initiate the noise model from a fake backend.
  2. Clean the noise model from all noises. This requires some knowledge. Suppose that, as in the example above, I set thermal_relaxation to True and gate_error and readout_error to False. Does it mean that only T1 and T2 are now in play, or are there other active types of noise that I should be aware of? In addition, even if the user is interested only in T1, she'll still have to be aware that she must explicitly set T2 as well (and vice versa).
  3. Set the desired values of T1 and/or T2.

Because of these reservations, we're postponing the move to the new simulator in the tests of characterization experiments in qiskit-experiments. We'll be happy to replace our mock backends (which we don't like) with Aer, given a suitable interface.

yaelbh commented 2 years ago

In a conversation with Itamar, he has raised an additional related potential issue, however he has not verified it yet. It appears that, using fake backends like FakeVigo, we're required to specify instruction durations if the circuit contains gates that are not in the set of basis gates. And for gates that are in the set of the basis gates - does it mean that the thermal noise is applied also on them, according to the gate durations in fake backend's properties? We're interested in the thermal noise only in the delay gate.

chriseclectic commented 2 years ago

Currently there is no straightforward way to add custom delay noise to a noise model since it is handled different from other noises due to being a transpiler pass. I think one interim solution would to make some public noise model functions that return the basic device noise models constructed by Aer fake backends, but with args/kwargs allow you to specify all the parameter values (gate times, gate errors, t1, t2 etc) rather than requiring a backend properties object which is currently used to extract all these parameter values.

That said I think there as some misconceptions as to building this sort of noise mode. The steps you outlined in the issue look a bit wrong since you probably shouldn't be using NoiseModel.from_backend if you are planning to remove all the errors it produces. If you want a custom noise model you should build that noise model directly (and that might require the new functions suggested if that noise model is to include any transpiler based parameterized errors since they can't be added as gate errors). For your second question the from_backend noise model with thermal relaxation errors will include T1/T2 errors on all gates from the backends properties based on backend T1,T2 and gate duration values (see the docs).

Now back to your actual use case for experiments, if you only want to add relaxation errors you might not actually need a noise model at all because it can be entirely handled by the RelaxationNoisePass transpiler pass which can be configured with which gates to apply to and qubit T1/T2 values.

In general this transpiler pass should be applied to a scheduled circuit, which requires all gates in the circuit to have duration information to schedule. But if you only want to apply it to delays, and leave everything else unchanged (which assumes your circuit has been constructed to be correctly scheduled so that scheduling would not introduce any additional delays) you can do something like this to build and apply a custom pass:

from qiskit.providers.aer import AerSimulator
from qiskit.providers.aer.noise import RelaxationNoisePass
from qiskit import QuantumCircuit
from qiskit.circuit import Delay

# build delay noise pass for 1-qubit
# T1 = 50us, T2 = 50 us, dt = 1 ns
delay_pass = RelaxationNoisePass([50e-6], [50e-6], dt=1e-9, op_types=[Delay])

# Build a circuit with delay
qc = QuantumCircuit(1, 1)
qc.h(0)
qc.delay(10)  # dt units
qc.h(0)
qc.measure(0, 0)

# Apply delay noise
noise_qc = delay_pass(qc)

# Print circ
print(noise_qc.draw())

#     ┌───┐┌─────────────────┐┌─────────────────┐┌───┐┌─┐
#  q: ┤ H ├┤ Delay(1000[dt]) ├┤ Quantum_channel ├┤ H ├┤M├
#     └───┘└─────────────────┘└─────────────────┘└───┘└╥┘
#c: 1/═════════════════════════════════════════════════╩═
                                                      0 
# Run
result = AerSimulator().run(noise_qc).result()

If you wanted to also add noise to other gates, your backend would have to contain duration information so you can schedule the circuit and run the above pass, or you could pass them separately as transpiler args. Eg:

from qiskit.providers.aer.noise import RelaxationNoisePass
from qiskit import QuantumCircuit, transpile
from qiskit.circuit import Delay
from qiskit.circuit.library import CXGate, XGate, SXGate, IGate

# Basis gates and durations
basis_gates = ["x", "sx", "rz", "id", "delay"]
instruction_durations = [ # dt units
    ('x', [0], 50),
    ('sx', [0], 25),
    ('id', [0], 25),
    ('rz', [0], 0),
    ('measure', [0], 0, 'us')
]

# Qubit-0 Thermal relaxation noise pass
op_types = [XGate, SXGate, IGate, Delay]
relax_pass = RelaxationNoisePass(
    [50e-6], [50e-6], dt=1e-9, op_types=op_types)

# Schedule circuit
sched_qc = transpile(
    qc, basis_gates=basis_gates,
    scheduling_method='asap', instruction_durations=instruction_durations)

# Add relaxation noise to scheduled circuit
noise_circ = relax_pass(sched_qc)
print(noise_circ.draw())
     ┌─────────┐┌────┐┌─────────────────┐┌─────────┐┌─────────────────┐»
  q: ┤ Rz(π/2) ├┤ √X ├┤ Quantum_channel ├┤ Rz(π/2) ├┤ Delay(1000[dt]) ├»
     └─────────┘└────┘└─────────────────┘└─────────┘└─────────────────┘»
c: 1/══════════════════════════════════════════════════════════════════»
                                                                       »
«     ┌─────────────────┐┌─────────┐┌────┐┌─────────────────┐┌─────────┐┌─┐
«  q: ┤ Quantum_channel ├┤ Rz(π/2) ├┤ √X ├┤ Quantum_channel ├┤ Rz(π/2) ├┤M├
«     └─────────────────┘└─────────┘└────┘└─────────────────┘└─────────┘└╥┘
«c: 1/═══════════════════════════════════════════════════════════════════╩═
«        
yaelbh commented 2 years ago

@chriseclectic Can you please share the advantages of the transpiler pass, over other methods to simulate thermal noise? I can see two alternatives (perhaps they're the same thing):

  1. The noise model already supports (or at least used to support) simulation of thermal noise, according to a specified gate length. So one has to look for the length of the delay instruction in its parameter, and continue from there with the existing simulation.
  2. Ethan's work from the summer.
chriseclectic commented 2 years ago

Ethans work was a transpiler pass. Relaxation error on a delay gate is a parameterized noise model because it depends on a parameter of the instruction (the duration). There is no way to simulate parameterized noise in Aer without a transpiler pass or equivalent method to modify the circuits by insert the fixed QuantumError channels depending on the specific parameter values before they are sent to the simulator.

For non-parameterized gates you can use regular NoiseModel to add a fixed error for instructions based on its name and qubits. That same error is then applied to all gates matching that name and qubits regardless of any parameter values. This is why previously delay gates were not supported in the device noise model, since all the relaxation errors for other gates were computed in advance based on the backend properties and added to a noise model.

The NoiseModel return from NoiseModel.from_backend was patched in 0.10 as a special case to include a transpiler pass for adding the delay noise that is run automatically for circuits containing delay instructions when you do backend.run. But if you build your own NoiseModel not using from_backend there is currently no way to include this automatic pass so you must build your own transpiler pass and either call it directly, or make a simulator Backend subclasses that calls it automatically (which is what Ethan's backend did).

What I am saying is if you wanted a test backend that only includes relaxation noise, and not any of the other noises in device noise model, you could define NoiseRelaxationPass that implements the noise for all instructions (except measurement) as a single transpiler pass, and make this test backend subclass that calls it automatically as part of its run, and that backend wouldn't need any other noise model.