Yes you can: When you build a noise model the noise is defined with respect to the name or label of gate objects, so you can use the labelto create multiple versions of a single gate but reference different errors in a noise model (NB: the transpiler strips away label information when it unrolls a gate not in the basis gates set).
Selective noise on standard gates
For example: Suppose I wanted to create two version of a XGate gate.
from qiskit import *
from qiskit.extensions import XGate
from qiskit.providers.aer.noise import NoiseModel, errors
x_gate = XGate() # regular X gate
x1_gate = XGate(label="x1") # first labelled X gate
x2_gate = XGate(label="x2") # second labelled X gate
x1_error = errors.depolarizing_error(0.1, 1)
x2_error = errors.depolarizing_error(0.01, 1)
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(x1_error, x1_gate.label)
noise_model.add_all_qubit_quantum_error(x2_error, x2_gate.label)
noise_model.add_basis_gates(['x'])
print(noise_model)
This makes the noise model:
NoiseModel:
Basis gates: ['cx', 'id', 'u3', 'x']
Instructions with noise: ['x2', 'x1']
All-qubits errors: ['x1', 'x2']
Notice the line noise_model.add_basis_gates(['x'])
, since we added a label that isn't recognised as a standard basis gate, we have to tell the noise model that x
should be in our basis gates (Aside: I hope to streamline this a bit in future versions)
Now to use this in a circuit I could have:
qc = QuantumCircuit(3, 3)
qc.append(x_gate, [0]) # regular noise-free x gate
qc.append(x1_gate, [1]) # noisy x1 gate
qc.append(x2_gate, [2]) # noisy x2 gate
qc.measure([0, 1, 2], [0, 1, 2])
result = execute(qc, Aer.get_backend('qasm_simulator'),
basis_gates=basis_gates,
noise_model=noise_model).result()
result.get_counts(0)
# Returns something like:
{'101': 40, '111': 980, '011': 4}
So we can see that we have different noise for all 3 X gates.
Selective noise on arbitrary unitary gates
You can use this to build noisy or ideal versions of any standard gate, and for custom gates using the unitary
gate object. Below I will do same example but with the X gates applied as a unitary matrix using the same labels for the noise model. Note that I need to add 'unitary'
to the noise model basis gates so that the unitaries aren't converted into u3
gates:
from qiskit.extensions import UnitaryGate
x_mat = XGate().to_matrix()
qc = QuantumCircuit(3, 3)
qc.unitary(x_mat, [0], label='x')
qc.unitary(x_mat, [1], label='x1')
qc.unitary(x_mat, [2], label='x2')
qc.measure([0, 1, 2], [0, 1, 2])
# We need to add unitary to noise model basis gates
noise_model.add_basis_gates('unitary')
basis_gates = noise_model.basis_gates
result = execute(qc, Aer.get_backend('qasm_simulator'),
basis_gates=basis_gates,
noise_model=noise_model).result()
result.get_counts(0)
# Returns something like
{'101': 37, '111': 983, '011': 4}
Selective noise on reset and measurement
You can also make ideal / noisy measurements or resets using the above trick with a custom gate before measurement or after reset. Eg:
# Make a noisy measure instruction
from qiskit.extensions import IdGate
tmp = QuantumCircuit(1, 1)
tmp.append(IdGate(label='noise_meas'), [0])
tmp.measure(0, 0)
noise_meas = tmp.to_instruction() # convert tmp circuit to instruction
# Create a noise model
noise_model = NoiseModel()
meas_error = errors.depolarizing_error(0.1, 1)
noise_model.add_all_qubit_quantum_error(meas_error, 'noise_meas')
basis_gates = noise_model.basis_gates
# Example circuit
circuit = QuantumCircuit(2, 2)
circuit.measure([0], [0])
circuit.append(noise_meas, [1], [1])
result = execute(circuit, Aer.get_backend("qasm_simulator"),
basis_gates=basis_gates,
noise_model=noise_model).result()
result.get_counts(0)
# Returns something like
{'10': 55, '00': 969}
Selective noise with basic_device_noise_model
Finally a comment on using this with basic device noise model. This is a little tricky but can be done. The problem is that if you are not building a noise model from scratch (and so choosing your own labels) the standard unlabelled gates u1,u2,u3,cx
will be the noisy gates, and you can add custom labels for the ideal u1, u2, u3, cx gates.
The transpiler will always convert gates to the noisy u3 etc (eg x->u3) So if you want ideal x you must insert as u3 gate, because all labels of x gates will get unrolled to the noisy u3.