From c40f151fe46ccf66db20dcc4c80cf4bf28edaeea Mon Sep 17 00:00:00 2001 From: "Christopher J. Wood" Date: Wed, 24 Feb 2021 02:50:16 -0500 Subject: [PATCH 1/8] Fix noise sampling for conditional gates (#1154) (cherry picked from commit a2f29eedbfc2e74f0929f46672fdbde697c2c1c2) --- ...ix-conditional-noise-178f5d03b97a8dd5.yaml | 8 +++ src/noise/noise_model.hpp | 69 ++++++++++++------- test/terra/reference/ref_pauli_noise.py | 35 +++++++++- 3 files changed, 86 insertions(+), 26 deletions(-) create mode 100644 releasenotes/notes/fix-conditional-noise-178f5d03b97a8dd5.yaml diff --git a/releasenotes/notes/fix-conditional-noise-178f5d03b97a8dd5.yaml b/releasenotes/notes/fix-conditional-noise-178f5d03b97a8dd5.yaml new file mode 100644 index 0000000000..5feff33f54 --- /dev/null +++ b/releasenotes/notes/fix-conditional-noise-178f5d03b97a8dd5.yaml @@ -0,0 +1,8 @@ +--- +fixes: + - | + Fixes a bug ([#1153](https://github.com/Qiskit/qiskit-aer/issues/1153)) + where noise on conditional gates was always being applied regardless of + whether the conditional gate was actually applied based on the classical + register value. Now noise on a conditional gate will only be applied in + the case where the conditional gate is applied. diff --git a/src/noise/noise_model.hpp b/src/noise/noise_model.hpp index 36ad41c52e..04fbe78770 100644 --- a/src/noise/noise_model.hpp +++ b/src/noise/noise_model.hpp @@ -284,38 +284,57 @@ NoiseModel::param_gate_table_ = { NoiseModel::NoiseOps NoiseModel::sample_noise(const Operations::Op &op, RngEngine &rng) const { + // Noise operations + NoiseOps noise_ops; // Look to see if gate is a waltz gate for this error model + // NOTE this is deprecated and waltz gate noise sampling should be removed auto it = x90_gates_.find(op.name); if (it == x90_gates_.end()) { // Non-X90 based gate, run according to base model - return sample_noise_helper(op, rng); + noise_ops = sample_noise_helper(op, rng); + } else { + // Decompose ops in terms of their waltz implementation + auto gate = waltz_gate_table_.find(op.name); + if (gate != waltz_gate_table_.end()) { + switch (gate->second) { + case WaltzGate::u3: + noise_ops = sample_noise_x90_u3(op.qubits[0], + op.params[0], op.params[1], op.params[2], + rng); + break; + case WaltzGate::u2: + noise_ops = sample_noise_x90_u2(op.qubits[0], + op.params[0], op.params[1], + rng); + break; + case WaltzGate::x: + noise_ops = sample_noise_x90_u3(op.qubits[0], M_PI, 0., M_PI, rng); + break; + case WaltzGate::y: + noise_ops = sample_noise_x90_u3(op.qubits[0], M_PI, 0.5 * M_PI, 0.5 * M_PI, rng); + break; + case WaltzGate::h: + noise_ops = sample_noise_x90_u2(op.qubits[0], 0., M_PI, rng); + break; + default: + // The rest of the Waltz operations are noise free (u1 only) + noise_ops = {op}; + break; + } + } else { + // something went wrong if we end up here + throw std::invalid_argument("Invalid waltz gate."); + } } - // Decompose ops in terms of their waltz implementation - auto gate = waltz_gate_table_.find(op.name); - if (gate != waltz_gate_table_.end()) { - switch (gate->second) { - case WaltzGate::u3: - return sample_noise_x90_u3(op.qubits[0], - op.params[0], op.params[1], op.params[2], - rng); - case WaltzGate::u2: - return sample_noise_x90_u2(op.qubits[0], - op.params[0], op.params[1], - rng); - case WaltzGate::x: - return sample_noise_x90_u3(op.qubits[0], M_PI, 0., M_PI, rng); - case WaltzGate::y: - return sample_noise_x90_u3(op.qubits[0], M_PI, 0.5 * M_PI, 0.5 * M_PI, rng); - case WaltzGate::h: - return sample_noise_x90_u2(op.qubits[0], 0., M_PI, rng); - default: - // The rest of the Waltz operations are noise free (u1 only) - return {op}; + // If original op is conditional, make all the noise operations also conditional + if (op.conditional) { + for (auto& noise_op : noise_ops) { + noise_op.conditional = op.conditional; + noise_op.conditional_reg = op.conditional_reg; + noise_op.bfunc = op.bfunc; } - } else { - // something went wrong if we end up here - throw std::invalid_argument("Invalid waltz gate."); } + return noise_ops; } diff --git a/test/terra/reference/ref_pauli_noise.py b/test/terra/reference/ref_pauli_noise.py index e431c6fa63..9ee51632fa 100644 --- a/test/terra/reference/ref_pauli_noise.py +++ b/test/terra/reference/ref_pauli_noise.py @@ -64,6 +64,20 @@ def pauli_gate_error_circuits(): circuit.measure(qr, cr) circuits.append(circuit) + # 50% Pauli error on conditional gate that doesn't get applied + circuit = QuantumCircuit(qr, cr) + circuit.x(qr).c_if(cr, 1) + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + + # 50% Pauli error on conditional gate that does get applied + circuit = QuantumCircuit(qr, cr) + circuit.x(qr).c_if(cr, 0) + circuit.barrier(qr) + circuit.measure(qr, cr) + circuits.append(circuit) + # 25% Pauli-X error on spectator for CX gate on [0, 1] qr = QuantumRegister(3, 'qr') cr = ClassicalRegister(3, 'cr') @@ -106,6 +120,18 @@ def pauli_gate_error_noise_models(): noise_model.add_quantum_error(error, 'id', [0]) noise_models.append(noise_model) + # 50% Pauli error on conditional gate that doesn't get applied + error = pauli_error([('X', 0.5), ('I', 0.5)]) + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(error, 'x') + noise_models.append(noise_model) + + # 50% Pauli error on conditional gate that does get applied + error = pauli_error([('X', 0.5), ('I', 0.5)]) + noise_model = NoiseModel() + noise_model.add_all_qubit_quantum_error(error, 'x') + noise_models.append(noise_model) + # 25% Pauli-X error on spectator for CX gate on [0, 1] error = pauli_error([('XII', 0.25), ('III', 0.75)]) noise_model = NoiseModel() @@ -135,11 +161,18 @@ def pauli_gate_error_counts(shots, hex_counts=True): counts = [3 * shots / 4, shots / 4, 0, 0] counts_lists.append(counts) + # 50% Pauli error on conditional gate that doesn't get applied + counts = [shots, 0, 0, 0] + counts_lists.append(counts) + + # 50% Pauli error on conditional gate that does get applied + counts = 4 * [shots / 4] + counts_lists.append(counts) + # 25% Pauli-X error on spectator for CX gate on [0, 1] counts = [3 * shots / 4, 0, 0, 0, shots / 4, 0, 0, 0] counts_lists.append(counts) - # Convert to counts dict return [list2dict(i, hex_counts) for i in counts_lists] From c0a4a2825f9a9768930dad38e5f441417a3ba50e Mon Sep 17 00:00:00 2001 From: Hiroshi Horii Date: Thu, 25 Feb 2021 11:12:27 +0900 Subject: [PATCH 2/8] change default max_memory_mb from half to full system memory (#1152) (cherry picked from commit 1a6d5df89a2e016afbb33a2d7088e6100348a7c4) Conflicts: src/controllers/controller.hpp --- qiskit/providers/aer/backends/qasm_simulator.py | 2 +- qiskit/providers/aer/backends/statevector_simulator.py | 2 +- qiskit/providers/aer/backends/unitary_simulator.py | 2 +- src/controllers/controller.hpp | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/qiskit/providers/aer/backends/qasm_simulator.py b/qiskit/providers/aer/backends/qasm_simulator.py index adcdacb261..3e28d79495 100644 --- a/qiskit/providers/aer/backends/qasm_simulator.py +++ b/qiskit/providers/aer/backends/qasm_simulator.py @@ -142,7 +142,7 @@ class QasmSimulator(AerBackend): to store a state vector. If a state vector needs more, an error is thrown. In general, a state vector of n-qubits uses 2^n complex values (16 Bytes). If set to 0, the maximum will be automatically - set to half the system memory size (Default: 0). + set to the system memory size (Default: 0). * ``optimize_ideal_threshold`` (int): Sets the qubit threshold for applying circuit optimization passes on ideal circuits. diff --git a/qiskit/providers/aer/backends/statevector_simulator.py b/qiskit/providers/aer/backends/statevector_simulator.py index 449bcca3ec..9e792b0e05 100644 --- a/qiskit/providers/aer/backends/statevector_simulator.py +++ b/qiskit/providers/aer/backends/statevector_simulator.py @@ -81,7 +81,7 @@ class StatevectorSimulator(AerBackend): to store a state vector. If a state vector needs more, an error is thrown. In general, a state vector of n-qubits uses 2^n complex values (16 Bytes). If set to 0, the maximum will be automatically - set to half the system memory size (Default: 0). + set to the system memory size (Default: 0). * ``statevector_parallel_threshold`` (int): Sets the threshold that "n_qubits" must be greater than to enable OpenMP diff --git a/qiskit/providers/aer/backends/unitary_simulator.py b/qiskit/providers/aer/backends/unitary_simulator.py index f7d9b735d7..bc1dd0aa53 100644 --- a/qiskit/providers/aer/backends/unitary_simulator.py +++ b/qiskit/providers/aer/backends/unitary_simulator.py @@ -87,7 +87,7 @@ class UnitarySimulator(AerBackend): to store a state vector. If a state vector needs more, an error is thrown. In general, a state vector of n-qubits uses 2^n complex values (16 Bytes). If set to 0, the maximum will be automatically - set to half the system memory size (Default: 0). + set to the system memory size (Default: 0). * ``"statevector_parallel_threshold"`` (int): Sets the threshold that 2 * "n_qubits" must be greater than to enable OpenMP diff --git a/src/controllers/controller.hpp b/src/controllers/controller.hpp index ec93065adc..20179537b7 100755 --- a/src/controllers/controller.hpp +++ b/src/controllers/controller.hpp @@ -302,7 +302,7 @@ void Controller::clear_parallelization() { parallel_nested_ = false; explicit_parallelization_ = false; - max_memory_mb_ = get_system_memory_mb() / 2; + max_memory_mb_ = get_system_memory_mb(); } void Controller::set_parallelization_experiments( From de4971335c421ed74155994427977cd0a417512d Mon Sep 17 00:00:00 2001 From: merav-aharoni <46567124+merav-aharoni@users.noreply.github.com> Date: Wed, 3 Mar 2021 11:48:25 +0200 Subject: [PATCH 3/8] Fixed bug in sample_measure_using_probabilities (#1132) Co-authored-by: Victor Villar Co-authored-by: Christopher J. Wood (cherry picked from commit 72674296de7de6cfdf812595be33a2f6f637a29f) --- .../notes/issue1126-e2d51f660b0078db.yaml | 7 +++++++ .../matrix_product_state.hpp | 7 +++---- test/terra/reference/ref_measure.py | 19 +++++++++++++++++++ 3 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 releasenotes/notes/issue1126-e2d51f660b0078db.yaml diff --git a/releasenotes/notes/issue1126-e2d51f660b0078db.yaml b/releasenotes/notes/issue1126-e2d51f660b0078db.yaml new file mode 100644 index 0000000000..dde0ecfd45 --- /dev/null +++ b/releasenotes/notes/issue1126-e2d51f660b0078db.yaml @@ -0,0 +1,7 @@ +--- + +fixes: + - | + Fixed issue #1126: bug in reporting measurement of a single qubit. The bug + occured when copying the measured value to the output data structure. + diff --git a/src/simulators/matrix_product_state/matrix_product_state.hpp b/src/simulators/matrix_product_state/matrix_product_state.hpp index 9dc2e07d5a..6cb1f1f3f7 100644 --- a/src/simulators/matrix_product_state/matrix_product_state.hpp +++ b/src/simulators/matrix_product_state/matrix_product_state.hpp @@ -757,7 +757,6 @@ rvector_t State::measure_probs(const reg_t &qubits) const { std::vector State::sample_measure(const reg_t &qubits, uint_t shots, RngEngine &rng) { - // There are two alternative algorithms for sample measure // We choose the one that is optimal relative to the total number // of qubits,and the number of shots. @@ -820,11 +819,11 @@ sample_measure_using_probabilities(const reg_t &qubits, std::vector all_samples; all_samples.reserve(shots); for (int_t val : allbit_samples) { - reg_t allbit_sample = Utils::int2reg(val, 2, qreg_.num_qubits()); + reg_t allbit_sample = Utils::int2reg(val, 2, qubits.size()); reg_t sample; sample.reserve(qubits.size()); - for (uint_t qubit : qubits) { - sample.push_back(allbit_sample[qubit]); + for (uint_t j=0; j state + qr = QuantumRegister(3) + cr = ClassicalRegister(1) + circuit = QuantumCircuit(qr, cr) + circuit.h(0) + circuit.x(1) + circuit.cx(0, 2) + circuit.barrier(qr) + circuit.measure(1, 0) + if not allow_sampling: + circuit.barrier(qr) + circuit.i(qr) + circuits.append(circuit) + return circuits @@ -89,6 +103,8 @@ def measure_counts_deterministic(shots, hex_counts=True): targets.append({'0x2': shots}) # Measure |11> state targets.append({'0x3': shots}) + # Measure a single qubit (qubit 1) in |1> state + targets.append({'0x1': shots}) else: # Measure |00> state targets.append({'00': shots}) @@ -98,6 +114,9 @@ def measure_counts_deterministic(shots, hex_counts=True): targets.append({'10': shots}) # Measure |11> state targets.append({'11': shots}) + # Measure a single qubit (qubit 1) in |1> state + targets.append({'0x1': shots}) + return targets From b29ced45a8c8553809a396f65f3d5378d635faf5 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Fri, 26 Feb 2021 11:42:00 -0500 Subject: [PATCH 4/8] Add arm64 release wheel jobs (#1162) * Add arm64 release wheel jobs This commit adds a new CI job to publish precompiled binary wheels for linux on aarch64 (arm64). Since the latest numpy and scipy releases now publish wheels for aarch64 we can run CI jobs to do the same since we won't be spending all our CI time budget compiling upstream dependencies from source anymore (terra 0.17.0 will be publishing wheels aarch64 wheels too). This enables users running on linux aarch64 systems to install qiskit without having to compile everything from source anymore. To build these wheels this commit uses travis, which is the only CI system that offers non-x86 nodes. (cherry picked from commit 1063501dd9a371d75b762d06e60e352f978f4ea5) --- .travis.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000000..3a19882184 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,29 @@ +--- +notifications: + email: false + +cache: + pip: true + +os: linux +dist: bionic +language: python +python: 3.7 +jobs: + include: + - name: Build aarch64 wheels + arch: arm64 + services: + - docker + install: + - echo "" + env: + - CIBW_BEFORE_ALL_LINUX="yum install -y https://dl.fedoraproject.org/pub/epel/7/aarch64/Packages/e/epel-release-7-12.noarch.rpm && yum install -y openblas-devel" + - CIBW_SKIP="cp27-* cp34-* cp35-* pp*" + - TWINE_USERNAME=qiskit + - CIBW_TEST_COMMAND="python {project}/tools/verify_wheels.py" + if: tag IS present + script: + - pip install -U twine importlib-metadata keyring cibuildwheel==1.9.0 + - cibuildwheel --output-dir wheelhouse + - twine upload wheelhouse/* From e0fa9c8607bdaf1ecd873436cbc4ee6f2d97f38e Mon Sep 17 00:00:00 2001 From: Jessie Yu Date: Wed, 20 Jan 2021 15:51:45 -0500 Subject: [PATCH 5/8] add v2 provider backend (#1106) Modified to handle backwards compatibility with older versions of qiskit terra prior to the Backend abstract class existing. (cherry picked from commit 450ae9642e8d6eb67fbecb994a7cd78742c8e444) --- qiskit/providers/aer/noise/noise_model.py | 7 ++++++- .../aer/pulse/system_models/pulse_system_model.py | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/qiskit/providers/aer/noise/noise_model.py b/qiskit/providers/aer/noise/noise_model.py index 9a6af556f7..0bdb8cfd1a 100644 --- a/qiskit/providers/aer/noise/noise_model.py +++ b/qiskit/providers/aer/noise/noise_model.py @@ -19,6 +19,10 @@ from qiskit.circuit import Instruction from qiskit.providers import BaseBackend +try: + from qiskit.providers import Backend +except ImportError: + Backend = None from qiskit.providers.models import BackendProperties from ..backends.aerbackend import AerJSONEncoder @@ -269,7 +273,8 @@ def from_backend(cls, backend, Raises: NoiseError: If the input backend is not valid. """ - if isinstance(backend, BaseBackend): + if isinstance(backend, BaseBackend) or ( + Backend is not None and isinstance(backend, Backend)): properties = backend.properties() basis_gates = backend.configuration().basis_gates if not properties: diff --git a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py index 77582e8ffc..d59268929a 100644 --- a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py +++ b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py @@ -18,6 +18,10 @@ from warnings import warn from collections import OrderedDict from qiskit.providers import BaseBackend +try: + from qiskit.providers import Backend +except ImportError: + Backend = None from ...aererror import AerError from .hamiltonian_model import HamiltonianModel @@ -94,7 +98,8 @@ def from_backend(cls, backend, subsystem_list=None): AerError: If channel or u_channel_lo are invalid. """ - if not isinstance(backend, BaseBackend): + if not isinstance(backend, BaseBackend) or ( + Backend is not None and isinstance(backend, Backend)): raise AerError("{} is not a Qiskit backend".format(backend)) # get relevant information from backend From 73d3d16112a44509ad28015ea9ee93921f11c6b7 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Wed, 3 Mar 2021 15:39:29 -0500 Subject: [PATCH 6/8] Prepare 0.7.6 release This commit prepares the 0.7.6 release, it bumps the version string and adds release notes documenting what has been fixed. --- docs/conf.py | 2 +- qiskit/providers/aer/VERSION.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/conf.py b/docs/conf.py index 0a7bab94ea..cc1cc26550 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -46,7 +46,7 @@ # The short X.Y version version = '' # The full version, including alpha/beta/rc tags -release = '0.7.5' +release = '0.7.6' # -- General configuration --------------------------------------------------- diff --git a/qiskit/providers/aer/VERSION.txt b/qiskit/providers/aer/VERSION.txt index 8bd6ba8c5c..c006218557 100644 --- a/qiskit/providers/aer/VERSION.txt +++ b/qiskit/providers/aer/VERSION.txt @@ -1 +1 @@ -0.7.5 +0.7.6 From cf1b9e100b7b97afea0ce9beb69a5af395c70852 Mon Sep 17 00:00:00 2001 From: Matthew Treinish Date: Thu, 4 Mar 2021 07:30:37 -0500 Subject: [PATCH 7/8] Simplify try except logic for Backend During code review it was suggested to change the try except logic around importing Backend from terra that was added in the backport for PR #1106 for backwards compatibility with the minimum supported terra version to a simpler version using tuples. This commit makes that change to avoid a needlessly long if statement around isinstance checking backend objects. Co-authored-by: Christopher J. Wood --- qiskit/providers/aer/noise/noise_model.py | 8 ++++---- .../aer/pulse/system_models/pulse_system_model.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/qiskit/providers/aer/noise/noise_model.py b/qiskit/providers/aer/noise/noise_model.py index 0bdb8cfd1a..5df41c0609 100644 --- a/qiskit/providers/aer/noise/noise_model.py +++ b/qiskit/providers/aer/noise/noise_model.py @@ -20,9 +20,10 @@ from qiskit.circuit import Instruction from qiskit.providers import BaseBackend try: - from qiskit.providers import Backend + from qiskit.providers import Backend as _Backend + BACKEND = (BaseBackend, _Backend) except ImportError: - Backend = None + BACKEND = BaseBackend from qiskit.providers.models import BackendProperties from ..backends.aerbackend import AerJSONEncoder @@ -273,8 +274,7 @@ def from_backend(cls, backend, Raises: NoiseError: If the input backend is not valid. """ - if isinstance(backend, BaseBackend) or ( - Backend is not None and isinstance(backend, Backend)): + if isinstance(backend, BACKEND): properties = backend.properties() basis_gates = backend.configuration().basis_gates if not properties: diff --git a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py index d59268929a..915d1aad20 100644 --- a/qiskit/providers/aer/pulse/system_models/pulse_system_model.py +++ b/qiskit/providers/aer/pulse/system_models/pulse_system_model.py @@ -19,9 +19,10 @@ from collections import OrderedDict from qiskit.providers import BaseBackend try: - from qiskit.providers import Backend + from qiskit.providers import Backend as _Backend + Backend = (BaseBackend, _Backend) except ImportError: - Backend = None + Backend = BaseBackend from ...aererror import AerError from .hamiltonian_model import HamiltonianModel @@ -98,8 +99,7 @@ def from_backend(cls, backend, subsystem_list=None): AerError: If channel or u_channel_lo are invalid. """ - if not isinstance(backend, BaseBackend) or ( - Backend is not None and isinstance(backend, Backend)): + if not isinstance(backend, Backend): raise AerError("{} is not a Qiskit backend".format(backend)) # get relevant information from backend From b5c1dc17fc928f932d1869d6459c04afddf63ff7 Mon Sep 17 00:00:00 2001 From: Christopher Wood Date: Thu, 4 Mar 2021 11:05:00 -0500 Subject: [PATCH 8/8] Backport of part of #1168 When moving an AER::Vector set the size of the moved vector to 0. --- src/framework/linalg/vector.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/framework/linalg/vector.hpp b/src/framework/linalg/vector.hpp index 075ea74805..ab7e163073 100755 --- a/src/framework/linalg/vector.hpp +++ b/src/framework/linalg/vector.hpp @@ -203,6 +203,7 @@ template Vector::Vector(Vector &&other) noexcept : size_(other.size_), data_(other.data_) { other.data_ = nullptr; + other.size_ = 0; } //----------------------------------------------------------------------- @@ -214,6 +215,7 @@ template Vector &Vector::operator=(Vector &&other) noexcept { size_ = other.size_; data_ = other.data_; other.data_ = nullptr; + other.size_ = 0; return *this; }