Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Noise model inserter #239

Merged
merged 13 commits into from
Jul 31, 2019
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ Added
- Added support for conditional unitary, kraus, superop qobj instructions (\# 291)
- Add "validation_threshold" config parameter to Aer backends (\# 290)

- Noise model inserter module

Changed
-------

Expand Down
1 change: 1 addition & 0 deletions qiskit/providers/aer/noise/utils/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@
from .noise_transformation import NoiseTransformer
from .noise_transformation import approximate_quantum_error
from .noise_transformation import approximate_noise_model
from .noise_model_inserter import insert_noise
51 changes: 51 additions & 0 deletions qiskit/providers/aer/noise/utils/noise_model_inserter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
Noise model inserter module
The goal of this module is to add QuantumError gates (Kraus gates) to a circuit
based on a given noise model. The resulting circuit cannot be ran on a quantum computer
but can be handled correctly by simulators
"""
import qiskit.compiler


def insert_noise(circuits, noise_model, transpile=False):
"""
This function gets a circuit and a noise model and returns a new circuit
with the noises from the noise model inserted as Kraus gates in the new circuit
Args:
circuits (QuantumCircuit or list[QuantumCircuit]): The circuits to add noises to
noise_model (NoiseModel): The noise model containing the errors to add
transpile (Boolean): Should the circuit be transpiled into the noise model basis gates
Returns:
QuantumCircuit: The new circuit with the added Kraus gates
"""
is_circuits_list = isinstance(circuits, (list, tuple))
circuits = circuits if is_circuits_list else [circuits]
result_circuits = []
errors = noise_model._default_quantum_errors.items()
error_dict = {name: qubit_dict for (name, qubit_dict) in errors}
for circuit in circuits:
if transpile:
transpiled_circuit = qiskit.compiler.transpile(circuit,
basis_gates=noise_model.basis_gates)
else:
transpiled_circuit = circuit
result_circuit = circuit.copy(name=transpiled_circuit.name + '_with_noise')
result_circuit.data = []
for inst, qargs, cargs in transpiled_circuit.data:
result_circuit.data.append((inst, qargs, cargs))
if inst.name in error_dict.keys():
error = error_dict[inst.name]
result_circuit.append(error.to_instruction(), qargs)
result_circuits.append(result_circuit)
return result_circuits if is_circuits_list else result_circuits[0]
124 changes: 124 additions & 0 deletions test/terra/noise/test_noise_inserter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
"""
noise_model_inserter module tests
"""

from qiskit import QuantumRegister, QuantumCircuit
from qiskit.providers.aer.noise.utils import insert_noise
from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.aer.noise.errors.standard_errors import pauli_error
from qiskit.qasm import pi
import unittest

class TestNoiseInserter(unittest.TestCase):
def test_no_noise(self):
qr = QuantumRegister(3, 'qr')
circuit = QuantumCircuit(qr)
circuit.x(qr[0])
circuit.y(qr[1])
circuit.z(qr[2])

target_circuit = QuantumCircuit(qr)
target_circuit.x(qr[0])
target_circuit.y(qr[1])
target_circuit.z(qr[2])

noise_model = NoiseModel() #empty

result_circuit = insert_noise(circuit, noise_model)

self.assertEqual(target_circuit, result_circuit)

def test_simple_noise(self):
qr = QuantumRegister(3, 'qr')
circuit = QuantumCircuit(qr)
circuit.x(qr[0])
circuit.y(qr[1])
circuit.z(qr[2])

error_x = pauli_error([('Y', 0.25), ('I', 0.75)])
error_y = pauli_error([('X', 0.35), ('Z', 0.65)])
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(error_x, 'x')
noise_model.add_all_qubit_quantum_error(error_y, 'y')

target_circuit = QuantumCircuit(qr)
target_circuit.x(qr[0])
target_circuit.append(error_x.to_instruction(), [qr[0]])
target_circuit.y(qr[1])
target_circuit.append(error_y.to_instruction(), [qr[1]])
target_circuit.z(qr[2])

result_circuit = insert_noise(circuit, noise_model)

self.assertEqual(target_circuit, result_circuit)

def test_transpiling(self):
qr = QuantumRegister(3, 'qr')
circuit = QuantumCircuit(qr)
circuit.x(qr[0])
circuit.y(qr[1])
circuit.z(qr[2])

error_x = pauli_error([('Y', 0.25), ('I', 0.75)])
error_y = pauli_error([('X', 0.35), ('Z', 0.65)])
noise_model = NoiseModel()
noise_model.add_all_qubit_quantum_error(error_x, 'x')
noise_model.add_all_qubit_quantum_error(error_y, 'u1')

target_circuit = QuantumCircuit(qr)
target_circuit.x(qr[0])
target_circuit.append(error_x.to_instruction(), [qr[0]])
target_circuit.u3(pi, pi / 2, pi / 2, qr[1])
target_circuit.u1(pi, qr[2])
target_circuit.append(error_y.to_instruction(), [qr[2]])

result_circuit = insert_noise(circuit, noise_model, transpile=True)
self.assertEqual(target_circuit, result_circuit)

def test_multiple_inputs(self):
qr = QuantumRegister(1, 'qr')
circuit1 = QuantumCircuit(qr)
circuit1.x(qr[0])

circuit2 = QuantumCircuit(qr)
circuit2.y(qr[0])

circuits_list = [circuit1, circuit2]
circuits_tuple = (circuit1, circuit2)

noise_model = NoiseModel()
error_x = pauli_error([('Y', 0.25), ('I', 0.75)])
error_y = pauli_error([('X', 0.35), ('Z', 0.65)])
noise_model.add_all_qubit_quantum_error(error_x, 'x')
noise_model.add_all_qubit_quantum_error(error_y, 'y')

target_circuit1 = QuantumCircuit(qr)
target_circuit1.x(qr[0])
target_circuit1.append(error_x.to_instruction(), [qr[0]])

target_circuit2 = QuantumCircuit(qr)
target_circuit2.y(qr[0])
target_circuit2.append(error_y.to_instruction(), [qr[0]])

target_circuits = [target_circuit1, target_circuit2]
result_circuits = insert_noise(circuits_list, noise_model)
self.assertEqual(target_circuits, result_circuits)

target_circuits = [target_circuit1, target_circuit2]
result_circuits = insert_noise(circuits_tuple, noise_model)
self.assertEqual(target_circuits, result_circuits)


if __name__ == '__main__':
unittest.main()