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 transform #162

Merged
merged 29 commits into from
Apr 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
54bd21b
Previous stable version of the noise transformation module
gadial Apr 15, 2019
cb9581d
Previous stable version of the noise transformation unit tests
gadial Apr 15, 2019
d78be7d
Adding noise transformation to the noise package
gadial Apr 15, 2019
1f58bfd
Beginning noise transformation overhaul (tests are failing)
gadial Apr 15, 2019
b83b328
Unified interface for dict/list/string approximating operator input
gadial Apr 15, 2019
b4e4642
Bugfixes in quantum_error_to_kraus_operators
gadial Apr 15, 2019
e35a958
More bugfixes
gadial Apr 15, 2019
f39350f
add to_channel method to QuantumError
chriseclectic Apr 15, 2019
97aa883
remove inplace from QuantumError, ReadoutError
chriseclectic Apr 15, 2019
00f73ae
Using the new to_channel method for errors
gadial Apr 16, 2019
90b7872
small adjustments
gadial Apr 16, 2019
e3d1073
Beginning testing overhaul; 3 working tests with the new interface
gadial Apr 16, 2019
0e03ee6
Target channel matrix now computed via SuperOp
gadial Apr 16, 2019
593c5ac
Tests are now fully working
gadial Apr 16, 2019
1b9d4e1
Implementation of approximate_noise_model
gadial Apr 16, 2019
e8e554d
Now testing noise model transformation
gadial Apr 16, 2019
45efe0d
Noise transformer tests will be skipped unless cvxopt is installed; a…
gadial Apr 16, 2019
79e37e7
Added Clifford support
gadial Apr 17, 2019
210aa4c
Added support for approximate_noise_model
gadial Apr 17, 2019
3c88bb2
Documentation
gadial Apr 17, 2019
3e23dcc
Now generates noise approximation using unitaries if possible
gadial Apr 18, 2019
a843049
Restructure - add noise utils directory
gadial Apr 18, 2019
bf30c5c
Allow uppercase letters in named noises
gadial Apr 18, 2019
96850a0
Now when possible outputs error circuits instead of Kraus/Unitary
gadial Apr 22, 2019
efdd10d
Now represent all named operators using circuits
gadial Apr 22, 2019
e87ec92
Return files to master version
gadial Apr 22, 2019
e7f3fa8
Bugfix
gadial Apr 22, 2019
37fe2c3
Font fix
gadial Apr 22, 2019
ee3d632
Merge branch 'master' into noise_transform
chriseclectic Apr 22, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions qiskit/providers/aer/noise/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,17 @@
Amplitude damping error
Phase damping error
Combined phase and amplitude damping error

Noise Utilities
--------------
The `noise.utils` module contains utilities for noise models and errors including:
'approximate_quantum_error' for approximating a general quantum error via
a provided set of errors (e.g. approximating amplitude damping via reset errors)
'approximate_noise_model' for approximating all the errors in a nose model using
the same provided set of errors
"""

from .noise_model import NoiseModel
from . import errors
from . import device
from . import utils
2 changes: 1 addition & 1 deletion qiskit/providers/aer/noise/errors/errorutils.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,4 +622,4 @@ def kraus2instructions(kraus_ops, standard_gates, atol=ATOL_DEFAULT):
]
instructions.append(make_kraus_instruction(non_unitaries, qubits))
probabilities.append(prob_kraus)
return zip(instructions, probabilities)
return zip(instructions, probabilities)
12 changes: 12 additions & 0 deletions qiskit/providers/aer/noise/utils/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# -*- coding: utf-8 -*-

# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.

"""Noise utils for Qiskit Aer.
"""
from .noise_transformation import NoiseTransformer
from .noise_transformation import approximate_quantum_error
from .noise_transformation import approximate_noise_model
455 changes: 455 additions & 0 deletions qiskit/providers/aer/noise/utils/noise_transformation.py

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions requirements-dev.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ cmake
scikit-build
cython
asv
cvxopt
2 changes: 1 addition & 1 deletion test/terra/noise/test_quantum_error.py
Original file line number Diff line number Diff line change
Expand Up @@ -712,4 +712,4 @@ def test_to_channel_circuit(self):


if __name__ == '__main__':
unittest.main()
unittest.main()
191 changes: 191 additions & 0 deletions test/terra/test_noise_transformation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,191 @@
# Copyright 2019, IBM.
#
# This source code is licensed under the Apache License, Version 2.0 found in
# the LICENSE.txt file in the root directory of this source tree.
"""
NoiseTransformer class tests
"""

import unittest
import numpy
from qiskit.providers.aer.noise.errors.errorutils import standard_gate_unitary
from qiskit.providers.aer.noise import NoiseModel
from qiskit.providers.aer.noise.utils import NoiseTransformer
from qiskit.providers.aer.noise.utils import approximate_quantum_error
from qiskit.providers.aer.noise.utils import approximate_noise_model
from qiskit.providers.aer.noise.errors.standard_errors import amplitude_damping_error
from qiskit.providers.aer.noise.errors.standard_errors import reset_error
from qiskit.providers.aer.noise.errors.standard_errors import pauli_error

try:
import cvxopt
has_cvxopt = True
except ImportError:
has_cvxopt = False

@unittest.skipUnless(has_cvxopt, "Needs cvxopt to test")
class TestNoiseTransformer(unittest.TestCase):
def setUp(self):
self.ops = {'X': standard_gate_unitary('x'),
'Y': standard_gate_unitary('y'),
'Z': standard_gate_unitary('z'),
'H': standard_gate_unitary('h'),
'S': standard_gate_unitary('s')
}
self.n = NoiseTransformer()


def assertNoiseModelsAlmostEqual(self, lhs, rhs, places = 3):
self.assertNoiseDictsAlmostEqual(lhs._nonlocal_quantum_errors, rhs._nonlocal_quantum_errors, places=places)
self.assertNoiseDictsAlmostEqual(lhs._local_quantum_errors, rhs._local_quantum_errors, places=places)
self.assertNoiseDictsAlmostEqual(lhs._default_quantum_errors, rhs._default_quantum_errors, places=places)
self.assertNoiseDictsAlmostEqual(lhs._local_readout_errors, rhs._local_readout_errors, places=places)
if lhs._default_readout_error is not None:
self.assertTrue(rhs._default_readout_error is not None)
self.assertErrorsAlmostEqual(lhs._default_readout_error, rhs._default_readout_error, places=places)
else:
self.assertTrue(rhs._default_readout_error is None)

def assertNoiseDictsAlmostEqual(self, lhs, rhs, places=3):
keys = set(lhs.keys()).union(set(rhs.keys()))
for key in keys:
self.assertTrue(key in lhs.keys(), msg="Key {} is missing from lhs".format(key))
self.assertTrue(key in rhs.keys(), msg="Key {} is missing from rhs".format(key))
for (lhs_error, rhs_error) in zip (lhs[key], rhs[key]):
self.assertErrorsAlmostEqual(lhs_error, rhs_error, places=places)

def assertErrorsAlmostEqual(self, lhs, rhs, places = 3):
self.assertMatricesAlmostEqual(lhs.to_channel()._data, rhs.to_channel()._data, places)

def assertDictAlmostEqual(self, lhs, rhs, places = None):
keys = set(lhs.keys()).union(set(rhs.keys()))
for key in keys:
self.assertAlmostEqual(lhs.get(key), rhs.get(key), msg = "Not almost equal for key {}: {} !~ {}".format(key, lhs.get(key), rhs.get(key)), places = places)

def assertListAlmostEqual(self, lhs, rhs, places = None):
self.assertEqual(len(lhs), len(rhs), msg = "List lengths differ: {} != {}".format(len(lhs), len(rhs)))
for i in range(len(lhs)):
if isinstance(lhs[i], numpy.ndarray) and isinstance(rhs[i], numpy.ndarray):
self.assertMatricesAlmostEqual(lhs[i], rhs[i], places = places)
else:
self.assertAlmostEqual(lhs[i], rhs[i], places = places)

def assertMatricesAlmostEqual(self, lhs, rhs, places = None):
self.assertEqual(lhs.shape, rhs.shape, "Marix shapes differ: {} vs {}".format(lhs, rhs))
n, m = lhs.shape
for x in range(n):
for y in range(m):
self.assertAlmostEqual(lhs[x,y], rhs[x,y], places = places, msg="Matrices {} and {} differ on ({}, {})".format(lhs, rhs, x, y))


def test_transformation_by_pauli(self):
n = NoiseTransformer()
#polarization in the XY plane; we represent via Kraus operators
X = self.ops['X']
Y = self.ops['Y']
Z = self.ops['Z']
p = 0.22
theta = numpy.pi / 5
E0 = numpy.sqrt(1 - p) * numpy.array(numpy.eye(2))
E1 = numpy.sqrt(p) * (numpy.cos(theta) * X + numpy.sin(theta) * Y)
results = approximate_quantum_error((E0, E1), operator_dict={"X": X, "Y": Y, "Z": Z})
expected_results = pauli_error([('X', p*numpy.cos(theta)*numpy.cos(theta)),
('Y', p*numpy.sin(theta)*numpy.sin(theta)),
('Z', 0),
('I', 1-p)])
self.assertErrorsAlmostEqual(expected_results, results)


#now try again without fidelity; should be the same
n.use_honesty_constraint = False
results = approximate_quantum_error((E0, E1), operator_dict={"X": X, "Y": Y, "Z": Z})
self.assertErrorsAlmostEqual(expected_results, results)

def test_reset(self):
# approximating amplitude damping using relaxation operators
gamma = 0.23
error = amplitude_damping_error(gamma)
p = (gamma - numpy.sqrt(1 - gamma) + 1) / 2
q = 0
expected_results = reset_error(p,q)
results = approximate_quantum_error(error, operator_string="reset")
self.assertErrorsAlmostEqual(results, expected_results)

def test_transform(self):
X = self.ops['X']
Y = self.ops['Y']
Z = self.ops['Z']
p = 0.34
theta = numpy.pi / 7
E0 = numpy.sqrt(1 - p) * numpy.array(numpy.eye(2))
E1 = numpy.sqrt(p) * (numpy.cos(theta) * X + numpy.sin(theta) * Y)

results_dict = approximate_quantum_error((E0, E1), operator_dict={"X": X, "Y": Y, "Z": Z})
results_string = approximate_quantum_error((E0, E1), operator_string='pauli')
results_list = approximate_quantum_error((E0, E1), operator_list=[X, Y, Z])
results_tuple = approximate_quantum_error((E0, E1), operator_list=(X, Y, Z))

self.assertErrorsAlmostEqual(results_dict, results_string)
self.assertErrorsAlmostEqual(results_string, results_list)
self.assertErrorsAlmostEqual(results_list, results_tuple)

def test_fidelity(self):
n = NoiseTransformer()
expected_fidelity = {'X': 0, 'Y': 0, 'Z': 0, 'H': 0, 'S': 2}
for key in expected_fidelity:
self.assertAlmostEqual(expected_fidelity[key], n.fidelity([self.ops[key]]), msg = "Wrong fidelity for {}".format(key))

def test_approx_noise_model(self):
noise_model = NoiseModel()
gamma = 0.23
p = 0.4
q = 0.33
ad_error = amplitude_damping_error(gamma)
r_error = reset_error(p,q) #should be approximated as-is
noise_model.add_all_qubit_quantum_error(ad_error, 'iden x y s')
noise_model.add_all_qubit_quantum_error(r_error, 'iden z h')

result = approximate_noise_model(noise_model, operator_string="reset")

expected_result = NoiseModel()
gamma_p = (gamma - numpy.sqrt(1 - gamma) + 1) / 2
gamma_q = 0
ad_error_approx = reset_error(gamma_p, gamma_q)
expected_result.add_all_qubit_quantum_error(ad_error_approx, 'iden x y s')
expected_result.add_all_qubit_quantum_error(r_error, 'iden z h')

self.assertNoiseModelsAlmostEqual(expected_result, result)

def test_clifford(self):
x_p = 0.17
y_p = 0.13
z_p = 0.34
error = pauli_error([('X', x_p), ('Y', y_p), ('Z', z_p), ('I', 1 - (x_p + y_p + z_p))])
results = approximate_quantum_error(error, operator_string="clifford")
self.assertErrorsAlmostEqual(error, results)

def test_approx_names(self):
gamma = 0.23
error = amplitude_damping_error(gamma)
results_1 = approximate_quantum_error(error, operator_string="pauli")
results_2 = approximate_quantum_error(error, operator_string="Pauli")
self.assertErrorsAlmostEqual(results_1, results_2)

def test_errors(self):
gamma = 0.23
error = amplitude_damping_error(gamma)
# kraus error is legit, transform_channel_operators are not
with self.assertRaisesRegex(TypeError, "takes 1 positional argument but 2 were given"):
approximate_quantum_error(error, 7)
with self.assertRaisesRegex(RuntimeError, "No information about noise type seven"):
approximate_quantum_error(error, operator_string="seven")

#let's pretend cvxopt does not exist; the script should raise ImportError with proper message
import unittest.mock
import sys
with unittest.mock.patch.dict(sys.modules, {'cvxopt': None}):
with self.assertRaisesRegex(ImportError, "The CVXOPT library is required to use this module"):
approximate_quantum_error(error, operator_string="reset")

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