Merge pull request #149 from cjwood/feature/backend-options

Cleaning up names and doctrings
This commit is contained in:
CHRISTOPHER J. WOOD 2018-12-14 13:33:48 -05:00 committed by GitHub Enterprise
commit 4b0cddda0b
36 changed files with 816 additions and 534 deletions

View File

@ -5,9 +5,6 @@
# 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.
import os
from pathlib import Path
from .backends import Aer
from . import backends
from . import noise

View File

@ -22,7 +22,7 @@ from qiskit.qobj import QobjConfig
from qiskit.result import Result
from .aerjob import AerJob
from .aersimulatorerror import AerSimulatorError
from .aererror import AerError
# Logger
logger = logging.getLogger(__name__)
@ -66,7 +66,7 @@ class AerBackend(BaseBackend):
Raises:
FileNotFoundError if backend executable is not available.
QISKitError: if there is no name in the configuration
QiskitError: if there is no name in the configuration
"""
super().__init__(configuration, provider=provider)
self._controller = controller
@ -144,9 +144,9 @@ class AerBackend(BaseBackend):
# Check for error message in the failed circuit
for res in output.get('results'):
if not res.get('success', False):
raise AerSimulatorError(res.get("status", None))
raise AerError(res.get("status", None))
# If no error was found check for error message at qobj level
raise AerSimulatorError(output.get("status", None))
raise AerError(output.get("status", None))
def _validate(self, qobj):
# TODO

View File

@ -6,13 +6,13 @@
# the LICENSE.txt file in the root directory of this source tree.
"""
Exception for errors raised by simulators.
Exception for errors raised by Qiskit Aer simulators backends.
"""
from qiskit import QISKitError
from qiskit.qiskiterror import QiskitError
class AerSimulatorError(QISKitError):
class AerError(QiskitError):
"""Base class for errors raised by simulators."""
def __init__(self, *message):

View File

@ -5,6 +5,8 @@
# 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.
# pylint: disable=arguments-differ
"""This module implements the job class used for AerBackend objects."""
import warnings
@ -39,7 +41,7 @@ def requires_submit(func):
class AerJob(BaseJob):
"""Aer Job class.
"""AerJob class.
Attributes:
_executor (futures.Executor): executor to handle asynchronous jobs
@ -118,22 +120,13 @@ class AerJob(BaseJob):
elif self._future.done():
_status = JobStatus.DONE if self._future.exception() is None else JobStatus.ERROR
else:
raise JobError('Unexpected behavior of {0}'.format(
self.__class__.__name__))
# Note: There is an undocumented Future state: PENDING, that seems to show up when
# the job is enqueued, waiting for someone to pick it up. We need to deal with this
# state but there's no public API for it, so we are assuming that if the job is not
# in any of the previous states, is PENDING, ergo INITIALIZING for us.
_status = JobStatus.INITIALIZING
return _status
def backend_name(self):
"""
Return the name of the backend used for this job.
.. deprecated:: 0.6+
After 0.6, this function is deprecated. Please use
`job.backend().name()` instead.
"""
warnings.warn('The use of `job.backend_name()` is deprecated, use '
'`job.backend().name()` instead.', DeprecationWarning)
return self._backend.name()
def backend(self):
"""Return the instance of the backend used for this job."""
return self._backend

View File

@ -19,12 +19,65 @@ from qasm_controller_wrapper import qasm_controller_execute
class QasmSimulator(AerBackend):
"""Aer quantum circuit simulator"""
"""Aer quantum circuit simulator
Backend options:
The following backend options may be used with in the
`backend_options` kwarg diction for `QasmSimulator.run` or
`qiskit.execute`
* "initial_statevector" (vector_like): Sets a custom initial
statevector for the simulation instead of the all zero
initial state (Default: None).
* "chop_threshold" (double): Sets the threshold for truncating small
values to zero in the Result data (Default: 1e-15)
* "max_parallel_threads" (int): Sets the maximum number of CPU
cores used by OpenMP for parallelization. If set to 0 the
maximum will be set to the number of CPU cores (Default: 0).
* "max_parallel_experiments" (int): Sets the maximum number of
qobj experiments that may be executed in parallel up to the
max_parallel_threads value. If set to 1 parallel circuit
execution will be disabled. If set to 0 the maximum will be
automatically set to max_parallel_threads (Default: 1).
* "max_parallel_shots" (int): Sets the maximum number of
shots that may be executed in parallel during each experiment
execution, up to the max_parallel_threads value. If set to 1
parallel shot execution wil be disabled. If set to 0 the
maximum will be automatically set to max_parallel_threads.
Note that this cannot be enabled at the same time as parallel
experiment execution (Default: 1).
* "statevector_parallel_threshold" (int): Sets the threshold that
"n_qubits" must be greater than to enable OpenMP
parallelization for matrix multiplication during execution of
an experiment. If parallel circuit or shot execution is enabled
this will only use unallocated CPU cores up to
max_parallel_threads. Note that setting this too low can reduce
performance (Default: 12).
* "statevector_sample_measure_opt" (int): Sets the threshold that
the number of qubits must be greater than to enable a large
qubit optimized implementation of measurement sampling. Note
that setting this two low can reduce performance (Default: 10)
* "statevector_hpc_gate_opt" (bool): If set to True this enables
a different optimzied gate application routine that can
increase performance on systems with a large number of CPU
cores. For systems with a small number of cores it enabling
can reduce performance (Default: False).
"""
MAX_QUBIT_MEMORY = int(log2(local_hardware_info()['memory'] * (1024 ** 3) / 16))
DEFAULT_CONFIGURATION = {
'backend_name': 'qasm_simulator',
'backend_version': __version__,
'n_qubits': int(log2(local_hardware_info()['memory'] * (1024 ** 3) / 16)),
'n_qubits': MAX_QUBIT_MEMORY,
'url': 'TODO',
'simulator': True,
'local': True,
@ -32,12 +85,33 @@ class QasmSimulator(AerBackend):
'open_pulse': False,
'memory': True,
'max_shots': 100000,
'description': 'A C++ simulator for QASM experiments with noise',
'description': 'A C++ simulator with realistic for qobj files',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z',
'h', 's', 'sdg', 't', 'tdg', 'ccx', 'swap', 'snapshot'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
'h', 's', 'sdg', 't', 'tdg', 'ccx', 'swap',
'snapshot', 'unitary'],
'gates': [
{
'name': 'TODO',
'parameters': [],
'qasm_def': 'TODO'
}
]
}
def run(self, qobj, backend_options=None, noise_model=None):
"""Run a qobj on the backend.
Args:
qobj (Qobj): a Qobj.
backend_options (dict): backend configuration options.
noise_model (NoiseModel): noise model for simulations.
Returns:
AerJob: the simulation job.
"""
return super().run(qobj, backend_options=backend_options,
noise_model=noise_model)
def __init__(self, configuration=None, provider=None):
super().__init__(qasm_controller_execute,
BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION),

View File

@ -25,12 +25,52 @@ logger = logging.getLogger(__name__)
class StatevectorSimulator(AerBackend):
"""Aer statevector simulator"""
"""Aer statevector simulator
Backend options:
The following backend options may be used with in the
`backend_options` kwarg diction for `StatevectorSimulator.run` or
`qiskit.execute`
* "initial_statevector" (vector_like): Sets a custom initial
statevector for the simulation instead of the all zero
initial state (Default: None).
* "chop_threshold" (double): Sets the threshold for truncating small
values to zero in the Result data (Default: 1e-15)
* "max_parallel_threads" (int): Sets the maximum number of CPU
cores used by OpenMP for parallelization. If set to 0 the
maximum will be set to the number of CPU cores (Default: 0).
* "max_parallel_experiments" (int): Sets the maximum number of
qobj experiments that may be executed in parallel up to the
max_parallel_threads value. If set to 1 parallel circuit
execution will be disabled. If set to 0 the maximum will be
automatically set to max_parallel_threads (Default: 1).
* "statevector_parallel_threshold" (int): Sets the threshold that
"n_qubits" must be greater than to enable OpenMP
parallelization for matrix multiplication during execution of
an experiment. If parallel circuit or shot execution is enabled
this will only use unallocated CPU cores up to
max_parallel_threads. Note that setting this too low can reduce
performance (Default: 12).
* "statevector_hpc_gate_opt" (bool): If set to True this enables
a different optimzied gate application routine that can
increase performance on systems with a large number of CPU
cores. For systems with a small number of cores it enabling
can reduce performance (Default: False).
"""
MAX_QUBIT_MEMORY = int(log2(local_hardware_info()['memory'] * (1024 ** 3) / 16))
DEFAULT_CONFIGURATION = {
'backend_name': 'statevector_simulator',
'backend_version': __version__,
'n_qubits': int(log2(local_hardware_info()['memory'] * (1024 ** 3) / 16)),
'n_qubits': MAX_QUBIT_MEMORY,
'url': 'TODO',
'simulator': True,
'local': True,
@ -38,10 +78,17 @@ class StatevectorSimulator(AerBackend):
'open_pulse': False,
'memory': True,
'max_shots': 1,
'description': 'A C++ statevector simulator for QASM experiments',
'description': 'A C++ statevector simulator for qobj files',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z',
'h', 's', 'sdg', 't', 'tdg', 'ccx', 'swap', 'snapshot'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
'h', 's', 'sdg', 't', 'tdg', 'ccx', 'swap',
'snapshot', 'unitary'],
'gates': [
{
'name': 'TODO',
'parameters': [],
'qasm_def': 'TODO'
}
]
}
def __init__(self, configuration=None, provider=None):
@ -50,7 +97,15 @@ class StatevectorSimulator(AerBackend):
provider=provider)
def run(self, qobj, backend_options=None):
"""Run a qobj on the backend."""
"""Run a qobj on the backend.
Args:
qobj (Qobj): a Qobj.
backend_options (dict): backend configuration options.
Returns:
AerJob: the simulation job.
"""
return super().run(qobj, backend_options=backend_options)
def _validate(self, qobj):

View File

@ -12,13 +12,13 @@ Qiskit Aer Unitary Simulator Backend.
"""
import logging
from math import log2
from math import log2, sqrt
from qiskit._util import local_hardware_info
from qiskit.backends.models import BackendConfiguration
from ..version import __version__
from .aerbackend import AerBackend
from .aersimulatorerror import AerSimulatorError
from .aererror import AerError
from unitary_controller_wrapper import unitary_controller_execute
# Logger
@ -26,23 +26,64 @@ logger = logging.getLogger(__name__)
class UnitarySimulator(AerBackend):
"""Unitary circuit simulator."""
"""Unitary circuit simulator.
Backend options:
The following backend options may be used with in the
`backend_options` kwarg diction for `UnitarySimulator.run` or
`qiskit.execute`
* "initial_unitary" (matrix_like): Sets a custom initial unitary
matrix for the simulation instead of identity (Default: None).
* "chop_threshold" (double): Sets the threshold for truncating small
values to zero in the Result data (Default: 1e-15)
* "max_parallel_threads" (int): Sets the maximum number of CPU
cores used by OpenMP for parallelization. If set to 0 the
maximum will be set to the number of CPU cores (Default: 0).
* "max_parallel_experiments" (int): Sets the maximum number of
qobj experiments that may be executed in parallel up to the
max_parallel_threads value. If set to 1 parallel circuit
execution will be disabled. If set to 0 the maximum will be
automatically set to max_parallel_threads (Default: 1).
* "unitary_parallel_threshold" (int): Sets the threshold that
"n_qubits" must be greater than to enable OpenMP
parallelization for matrix multiplication during execution of
an experiment. If parallel circuit execution is enabled this
will only use unallocated CPU cores up to max_parallel_threads.
Note that setting this too low can reduce performance
(Default: 6).
"""
MAX_QUBITS_MEMORY = int(log2(sqrt(local_hardware_info()['memory'] * (1024 ** 3) / 16)))
DEFAULT_CONFIGURATION = {
'backend_name': 'unitary_simulator',
'backend_version': __version__,
'n_qubits': int(log2(local_hardware_info()['memory'] * (1024 ** 3) / 16)),
'url': 'TODO',
'n_qubits': MAX_QUBITS_MEMORY,
'url': 'https://github.com/Qiskit/qiskit-aer',
'simulator': True,
'local': True,
'conditional': False,
'open_pulse': False,
'memory': False,
'max_shots': 1,
'description': 'A C++ unitary simulator for QASM experiments',
'description': 'A Python simulator for computing the unitary' +
'matrix for experiments in qobj files',
'basis_gates': ['u1', 'u2', 'u3', 'cx', 'cz', 'id', 'x', 'y', 'z',
'h', 's', 'sdg', 't', 'tdg', 'ccx', 'swap', 'snapshot'],
'gates': [{'name': 'TODO', 'parameters': [], 'qasm_def': 'TODO'}]
'h', 's', 'sdg', 't', 'tdg', 'ccx', 'swap',
'snapshot', 'unitary'],
'gates': [
{
'name': 'TODO',
'parameters': [],
'qasm_def': 'TODO'
}
]
}
def __init__(self, configuration=None, provider=None):
@ -51,7 +92,15 @@ class UnitarySimulator(AerBackend):
provider=provider)
def run(self, qobj, backend_options=None):
"""Run a qobj on the backend."""
"""Run a qobj on the backend.
Args:
qobj (Qobj): a Qobj.
backend_options (dict): backend configuration options.
Returns:
AerJob: the simulation job.
"""
return super().run(qobj, backend_options=backend_options)
def _validate(self, qobj):
@ -69,9 +118,9 @@ class UnitarySimulator(AerBackend):
# Check for measure or reset operations
for pos, instr in reversed(list(enumerate(experiment.instructions))):
if instr.name == "measure":
raise AerSimulatorError("UnitarySimulator: circuit contains measure.")
raise AerError("UnitarySimulator: circuit contains measure.")
if instr.name == "reset":
raise AerSimulatorError("UnitarySimulator: circuit contains reset.")
raise AerError("UnitarySimulator: circuit contains reset.")
# Set shots to 1
if getattr(experiment.config, 'shots', 1) != 1:
logger.info("UnitarySimulator only supports 1 shot. "

View File

@ -40,32 +40,30 @@ Custom Noise Models
-------------------
Custom noise models may be constructed by adding errors to a NoiseModel
object. Errors are represented using by the `QuantumError` and
`ReadoutError` classes:
`ReadoutError` classes from the `noise.errors` module:
* `QuantumErrors`: Errors that affect the quantum state during a
* `QuantumError`: Errors that affect the quantum state during a
simulation. They may be applied after specific circuit gates or
reset operations, or before measure operations of qubits.
* `ReadoutErrors`: Errors that apply to classical bit registers
* `ReadoutError`: Errors that apply to classical bit registers
after a measurement. They do not change the quantum state of the
system, only the recorded classical measurement outcome.
Helper functions exist for generating standard quantum error channels in
the `errors` submodule. These functions are:
the `noise.errors` module. These functions are:
* `errors.kraus_error`
* `errors.mixed_unitary_error`
* `errors.coherent_unitary_error`
* `errors.pauli_error`
* `errors.depolarizing_error`
* `errors.thermal_relaxation_error`
* `errors.phase_amplitude_damping_error`
* `errors.amplitude_damping_error`
* `errors.phase_damping_error`
* `kraus_error`
* `mixed_unitary_error`
* `coherent_unitary_error`
* `pauli_error`
* `depolarizing_error`
* `thermal_relaxation_error`
* `phase_amplitude_damping_error`
* `amplitude_damping_error`
* `phase_damping_error`
"""
from .noise_model import NoiseModel
from .quantum_error import QuantumError
from .readout_error import ReadoutError
from . import errors
from . import device

View File

@ -17,7 +17,7 @@ from .parameters import gate_error_values
from .parameters import thermal_relaxation_values
from ..noise_model import NoiseModel
from ..readout_error import ReadoutError
from ..errors.readout_error import ReadoutError
from ..errors.standard_errors import depolarizing_error
from ..errors.standard_errors import thermal_relaxation_error

View File

@ -10,7 +10,7 @@ Helper functions for noise model creation.
"""
import numpy as np
from .aernoiseerror import AerNoiseError
from ..noiseerror import NoiseError
def standard_gates_instructions(instructions):
@ -117,7 +117,7 @@ def single_qubit_clifford_gates(j):
tuple(str): The tuple of basis gates."""
if not isinstance(j, int) or j < 0 or j > 23:
raise AerNoiseError("Index {} must be in the range [0, ..., 23]".format(j))
raise NoiseError("Index {} must be in the range [0, ..., 23]".format(j))
labels = [
('id',), ('s',), ('sdg',), ('z',),
@ -142,7 +142,7 @@ def single_qubit_clifford_matrix(j):
np.array: The matrix for the indexed clifford."""
if not isinstance(j, int) or j < 0 or j > 23:
raise AerNoiseError("Index {} must be in the range [0, ..., 23]".format(j))
raise NoiseError("Index {} must be in the range [0, ..., 23]".format(j))
basis_dict = {
'id': np.eye(2),
@ -174,9 +174,9 @@ def single_qubit_clifford_instructions(j, qubit=0):
list(dict): The list of instructions."""
if not isinstance(j, int) or j < 0 or j > 23:
raise AerNoiseError("Index {} must be in the range [0, ..., 23]".format(j))
raise NoiseError("Index {} must be in the range [0, ..., 23]".format(j))
if not isinstance(qubit, int) or qubit < 0:
raise AerNoiseError("qubit position must be positive integer.")
raise NoiseError("qubit position must be positive integer.")
instructions = []
for gate in single_qubit_clifford_gates(j):
@ -275,10 +275,10 @@ def make_unitary_instruction(mat, qubits, standard_gates=True):
dict: The qobj instruction object.
Raises:
AerNoiseError: if the input is not a unitary matrix.
NoiseError: if the input is not a unitary matrix.
"""
if not is_unitary_matrix(mat):
raise AerNoiseError("Input matrix is not unitary.")
raise NoiseError("Input matrix is not unitary.")
elif isinstance(qubits, int):
qubits = [qubits]
instruction = {"name": "unitary",
@ -300,10 +300,10 @@ def make_kraus_instruction(mats, qubits):
dict: The qobj instruction object.
Raises:
AerNoiseError: if the input is not a CPTP Kraus channel.
NoiseError: if the input is not a CPTP Kraus channel.
"""
if not is_cptp_kraus(mats):
raise AerNoiseError("Input Kraus matrices are not a CPTP channel.")
raise NoiseError("Input Kraus matrices are not a CPTP channel.")
elif isinstance(qubits, int):
qubits = [qubits]
return [{"name": "kraus", "qubits": qubits, "params": mats}]
@ -315,7 +315,7 @@ def qubits_from_mat(mat):
shape = arr.shape
num_qubits = int(np.log2(shape[1]))
if shape[1] != 2 ** num_qubits:
raise AerNoiseError("Input Kraus channel is not a multi-qubit channel.")
raise NoiseError("Input Kraus channel is not a multi-qubit channel.")
return num_qubits
@ -384,9 +384,9 @@ def choi2kraus(choi, threshold=1e-10):
"""Convert a Choi matrix to canonical Kraus matrices"""
# Check threshold
if threshold < 0:
raise AerNoiseError("Threshold value cannot be negative")
raise NoiseError("Threshold value cannot be negative")
if threshold > 1e-3:
raise AerNoiseError("Threshold value is too large. It should be close to zero.")
raise NoiseError("Threshold value is too large. It should be close to zero.")
# Compute eigensystem of Choi matrix
w, v = np.linalg.eig(choi)
kraus = []
@ -394,7 +394,7 @@ def choi2kraus(choi, threshold=1e-10):
if val > threshold:
kraus.append(np.sqrt(val) * vec.reshape((2, 2), order='F'))
if val < -threshold:
raise AerNoiseError("Input Choi-matrix is not CP " +
raise NoiseError("Input Choi-matrix is not CP " +
" (eigenvalue {} < 0)".format(val))
return kraus
@ -434,22 +434,22 @@ def kraus2instructions(kraus_ops, standard_gates, threshold):
given error.
Raises:
AerNoiseError: If the input Kraus channel is not CPTP.
NoiseError: If the input Kraus channel is not CPTP.
"""
# Check threshold
if threshold < 0:
raise AerNoiseError("Threshold cannot be negative")
raise NoiseError("Threshold cannot be negative")
if threshold > 1e-3:
raise AerNoiseError("Threhsold value is too large. It should be close to zero.")
raise NoiseError("Threhsold value is too large. It should be close to zero.")
# Check CPTP
if not is_cptp_kraus(kraus_ops):
raise AerNoiseError("Input Kraus channel is not CPTP.")
raise NoiseError("Input Kraus channel is not CPTP.")
# Get number of qubits
num_qubits = int(np.log2(len(kraus_ops[0])))
if len(kraus_ops[0]) != 2 ** num_qubits:
raise AerNoiseError("Input Kraus channel is not a multi-qubit channel.")
raise NoiseError("Input Kraus channel is not a multi-qubit channel.")
# Check if each matrix is a:
# 1. scaled identity matrix
@ -492,22 +492,22 @@ def kraus2instructions(kraus_ops, standard_gates, threshold):
# Check probabilities
prob_kraus = 1 - prob_unitary
if prob_unitary - 1 > threshold:
raise AerNoiseError("Invalid kraus matrices: unitary probability" +
raise NoiseError("Invalid kraus matrices: unitary probability" +
" {} > 1".format(prob_unitary))
if prob_unitary < -threshold:
raise AerNoiseError("Invalid kraus matrices: unitary probability" +
raise NoiseError("Invalid kraus matrices: unitary probability" +
" {} < 1".format(prob_unitary))
if prob_identity - 1 > threshold:
raise AerNoiseError("Invalid kraus matrices: identity probability" +
raise NoiseError("Invalid kraus matrices: identity probability" +
" {} > 1".format(prob_identity))
if prob_identity < -threshold:
raise AerNoiseError("Invalid kraus matrices: identity probability" +
raise NoiseError("Invalid kraus matrices: identity probability" +
" {} < 1".format(prob_identity))
if prob_kraus - 1 > threshold:
raise AerNoiseError("Invalid kraus matrices: non-unitary probability" +
raise NoiseError("Invalid kraus matrices: non-unitary probability" +
" {} > 1".format(prob_kraus))
if prob_kraus < -threshold:
raise AerNoiseError("Invalid kraus matrices: non-unitary probability" +
raise NoiseError("Invalid kraus matrices: non-unitary probability" +
" {} < 1".format(prob_kraus))
# Build qobj instructions

View File

@ -10,8 +10,8 @@ Quantum error class for Qiskit Aer noise model
"""
import logging
import numpy as np
from .aernoiseerror import AerNoiseError
from .noise_utils import kraus2instructions
from ..noiseerror import NoiseError
from .errorutils import kraus2instructions
logger = logging.getLogger(__name__)
@ -93,15 +93,15 @@ class QuantumError:
# Error checking
if minimum_qubits > self._number_of_qubits:
raise AerNoiseError("Input errors require {} qubits, ".format(minimum_qubits) +
raise NoiseError("Input errors require {} qubits, ".format(minimum_qubits) +
"but number_of_qubits is {}".format(number_of_qubits))
if len(self._noise_circuits) != len(self._noise_probabilities):
raise AerNoiseError("Number of error circuits does not match length of probabilities")
raise NoiseError("Number of error circuits does not match length of probabilities")
total_probs = np.sum(self._noise_probabilities)
if abs(total_probs - 1) > threshold:
raise AerNoiseError("Probabilities are not normalized: {} != 1".format(total_probs))
raise NoiseError("Probabilities are not normalized: {} != 1".format(total_probs))
if len([p for p in self._noise_probabilities if p < 0]) > 0:
raise AerNoiseError("Probabilities are invalid.")
raise NoiseError("Probabilities are invalid.")
def __repr__(self):
"""Display QuantumError."""
@ -155,13 +155,13 @@ class QuantumError:
is the list of qobj instructions for the error term.
Raises:
AerNoiseError: If the position is greater than the size of
NoiseError: If the position is greater than the size of
the quantum error.
"""
if position < self.size:
return self.circuits[position], self.probabilities[position]
else:
raise AerNoiseError("Position {} is greater than the number".format(position) +
raise NoiseError("Position {} is greater than the number".format(position) +
"of error outcomes {}".format(self.size))
def as_dict(self):
@ -192,9 +192,9 @@ class QuantumError:
"""
# Error checking
if not isinstance(error, QuantumError):
raise AerNoiseError("error1 is not a QuantumError")
raise NoiseError("error1 is not a QuantumError")
if self.number_of_qubits != error.number_of_qubits:
raise AerNoiseError("QuantumErrors are not defined on same number of qubits.")
raise NoiseError("QuantumErrors are not defined on same number of qubits.")
combined_noise_circuits = []
combined_noise_probabilities = []
@ -256,7 +256,7 @@ class QuantumError:
# Error checking
if not isinstance(error, QuantumError):
raise AerNoiseError("{} is not a QuantumError".format(error))
raise NoiseError("{} is not a QuantumError".format(error))
combined_noise_circuits = []
combined_noise_probabilities = []
@ -326,7 +326,7 @@ class QuantumError:
qubits0 = kraus0['qubits']
qubits1 = kraus1['qubits']
if qubits0 != qubits1:
raise AerNoiseError("Kraus instructions are on different qubits")
raise NoiseError("Kraus instructions are on different qubits")
params = [np.dot(b, a) for a in kraus0['params']
for b in kraus1['params']]
return {'name': 'kraus', 'qubits': qubits0, 'params': params}
@ -336,7 +336,7 @@ class QuantumError:
qubits0 = mat0['qubits']
qubits1 = mat1['qubits']
if qubits0 != qubits1:
raise AerNoiseError("Unitary instructions are on different qubits")
raise NoiseError("Unitary instructions are on different qubits")
params = np.dot(mat1['params'], mat0['params'])
return {'name': 'unitary', 'qubits': qubits0, 'params': params}

View File

@ -12,8 +12,8 @@ Readout error class for Qiskit Aer noise model.
from numpy import array, log2, eye
from numpy.linalg import norm
from .noise_utils import qubits_from_mat
from .aernoiseerror import AerNoiseError
from ..noiseerror import NoiseError
from .errorutils import qubits_from_mat
class ReadoutError:
@ -78,23 +78,23 @@ class ReadoutError:
def _check_probabilities(probabilities, threshold):
"""Check probabilities are valid."""
if len(probabilities) == 0:
raise AerNoiseError("Input probabilities: empty.")
raise NoiseError("Input probabilities: empty.")
num_outcomes = len(probabilities[0])
num_qubits = int(log2(num_outcomes))
if 2 ** num_qubits != num_outcomes:
raise AerNoiseError("Invalid probabilities: length" +
raise NoiseError("Invalid probabilities: length" +
"{} != 2**{}".format(num_outcomes, num_qubits))
if len(probabilities) != num_outcomes:
raise AerNoiseError("Invalid probabilities.")
raise NoiseError("Invalid probabilities.")
for vec in probabilities:
arr = array(vec)
if len(arr) != num_outcomes:
raise AerNoiseError("Invalid probabilities: vectors are different lengths.")
raise NoiseError("Invalid probabilities: vectors are different lengths.")
if abs(sum(arr) - 1) > threshold:
raise AerNoiseError("Invalid probabilities: sum({})".format(vec) +
raise NoiseError("Invalid probabilities: sum({})".format(vec) +
" = {} is not 1.".format(sum(arr)))
if len(arr[arr < 0]) > 0:
raise AerNoiseError("Invalid probabilities: {}".format(vec) +
raise NoiseError("Invalid probabilities: {}".format(vec) +
" contains a negative probability.")
def __repr__(self):

View File

@ -13,16 +13,15 @@ import numpy as np
from itertools import product
from qiskit.quantum_info.operators.pauli import Pauli
from ..aernoiseerror import AerNoiseError
from ..quantum_error import QuantumError
from ..noise_utils import make_unitary_instruction
from ..noise_utils import qubits_from_mat
from ..noise_utils import canonical_kraus_matrices
from ..noise_utils import choi2kraus
from ..noise_utils import standard_gate_unitary
from ..noise_utils import is_unitary_matrix
from ..noise_utils import is_identity_matrix
from ..noiseerror import NoiseError
from .errorutils import make_unitary_instruction
from .errorutils import qubits_from_mat
from .errorutils import canonical_kraus_matrices
from .errorutils import choi2kraus
from .errorutils import standard_gate_unitary
from .errorutils import is_unitary_matrix
from .errorutils import is_identity_matrix
from .quantum_error import QuantumError
def kraus_error(noise_ops, standard_gates=True, canonical_kraus=False):
"""Kraus error channel.
@ -37,12 +36,12 @@ def kraus_error(noise_ops, standard_gates=True, canonical_kraus=False):
QuantumError: The quantum error object.
Raises:
AerNoiseError: if error parameters are invalid.
NoiseError: if error parameters are invalid.
"""
if not isinstance(noise_ops, (list, tuple)):
raise AerNoiseError("Invalid Kraus error input.")
raise NoiseError("Invalid Kraus error input.")
if len(noise_ops) == 0:
raise AerNoiseError("Kraus error noise_ops must not be empty.")
raise NoiseError("Kraus error noise_ops must not be empty.")
kraus_ops = [np.array(a, dtype=complex) for a in noise_ops]
if canonical_kraus:
kraus_ops = canonical_kraus_matrices(kraus_ops)
@ -65,17 +64,17 @@ def mixed_unitary_error(noise_ops, standard_gates=True):
QuantumError: The quantum error object.
Raises:
AerNoiseError: if error parameters are invalid.
NoiseError: if error parameters are invalid.
"""
# Error checking
if not isinstance(noise_ops, (list, tuple, zip)):
raise AerNoiseError("Input noise ops is not a list.")
raise NoiseError("Input noise ops is not a list.")
# Convert to numpy arrays
noise_ops = [(np.array(op, dtype=complex), p) for op, p in noise_ops]
if len(noise_ops) == 0:
raise AerNoiseError("Input noise list is empty.")
raise NoiseError("Input noise list is empty.")
# Check for identity unitaries
prob_identity = 0.
@ -86,9 +85,9 @@ def mixed_unitary_error(noise_ops, standard_gates=True):
for unitary, prob in noise_ops:
# Check unitary
if qubits_from_mat(unitary) != num_qubits:
raise AerNoiseError("Input matrices different size.")
raise NoiseError("Input matrices different size.")
if not is_unitary_matrix(unitary):
raise AerNoiseError("Input matrix is not unitary.")
raise NoiseError("Input matrix is not unitary.")
if is_identity_matrix(unitary):
prob_identity += prob
else:
@ -134,15 +133,15 @@ def pauli_error(noise_ops, standard_gates=False):
QuantumError: The quantum error object.
Raises:
AerNoiseError: If depolarizing probability is less than 0 or greater than 1.
NoiseError: If depolarizing probability is less than 0 or greater than 1.
"""
# Error checking
if not isinstance(noise_ops, (list, tuple, zip)):
raise AerNoiseError("Input noise ops is not a list.")
raise NoiseError("Input noise ops is not a list.")
noise_ops = list(noise_ops)
if len(noise_ops) == 0:
raise AerNoiseError("Input noise list is empty.")
raise NoiseError("Input noise list is empty.")
num_qubits = None
for op in noise_ops:
pauli = op[0]
@ -151,11 +150,11 @@ def pauli_error(noise_ops, standard_gates=False):
elif isinstance(pauli, str):
pauli_str = pauli
else:
raise AerNoiseError("Invalid Pauli input operator: {}".format(pauli))
raise NoiseError("Invalid Pauli input operator: {}".format(pauli))
if num_qubits is None:
num_qubits = len(pauli_str)
elif num_qubits != len(pauli_str):
raise AerNoiseError("Pauli's are not all of the same length.")
raise NoiseError("Pauli's are not all of the same length.")
# Compute Paulis as single matrix
if standard_gates is False:
@ -196,7 +195,7 @@ def _pauli_error_unitary(noise_ops, num_qubits):
mat = np.kron(single_pauli(s), mat)
qubits.append(qubit)
elif s != 'I':
raise AerNoiseError("Invalid Pauli string.")
raise NoiseError("Invalid Pauli string.")
if mat is 1:
prob_identity += prob
else:
@ -244,7 +243,7 @@ def _pauli_error_standard(noise_ops, num_qubits):
instruction["qubits"] = [qubit]
circuit.append(instruction)
elif s != 'I':
raise AerNoiseError("Invalid Pauli string.")
raise NoiseError("Invalid Pauli string.")
if circuit == []:
prob_identity += prob
else:
@ -276,7 +275,7 @@ def depolarizing_error(prob, num_qubits, standard_gates=False):
"""
if prob < 0 or prob > 1:
raise AerNoiseError("Depolarizing probability must be in between 0 and 1.")
raise NoiseError("Depolarizing probability must be in between 0 and 1.")
# Rescale completely depolarizing channel error probs
# with the identity component removed
@ -312,19 +311,19 @@ def thermal_relaxation_error(t1, t2, time, excited_state_population=0):
non-unitary Kraus error channel.
"""
if excited_state_population < 0:
raise AerNoiseError("Invalid excited state population " +
raise NoiseError("Invalid excited state population " +
"({} < 0).".format(excited_state_population))
if excited_state_population > 1:
raise AerNoiseError("Invalid excited state population " +
raise NoiseError("Invalid excited state population " +
"({} > 1).".format(excited_state_population))
if time < 0:
raise AerNoiseError("Invalid gate_time ({} < 0)".format(time))
raise NoiseError("Invalid gate_time ({} < 0)".format(time))
if t1 <= 0:
raise AerNoiseError("Invalid T_1 relaxation time parameter: T_1 <= 0.")
raise NoiseError("Invalid T_1 relaxation time parameter: T_1 <= 0.")
if t2 <= 0:
raise AerNoiseError("Invalid T_2 relaxation time parameter: T_2 <= 0.")
raise NoiseError("Invalid T_2 relaxation time parameter: T_2 <= 0.")
if t2 - 2 * t1 > 0:
raise AerNoiseError("Invalid T_2 relaxation time parameter: T_2 greater than 2 * T_1.")
raise NoiseError("Invalid T_2 relaxation time parameter: T_2 greater than 2 * T_1.")
# T1 relaxation rate
if t1 == np.inf:
@ -409,19 +408,19 @@ def phase_amplitude_damping_error(param_amp, param_phase,
"""
if param_amp < 0:
raise AerNoiseError("Invalid amplitude damping to |0> parameter " +
raise NoiseError("Invalid amplitude damping to |0> parameter " +
"({} < 0)".format(param_amp))
if param_phase < 0:
raise AerNoiseError("Invalid phase damping parameter " +
raise NoiseError("Invalid phase damping parameter " +
"({} < 0)".format(param_phase))
if param_phase + param_amp > 1:
raise AerNoiseError("Invalid amplitude and phase damping parameters " +
raise NoiseError("Invalid amplitude and phase damping parameters " +
"({} + {} > 1)".format(param_phase, param_amp))
if excited_state_population < 0:
raise AerNoiseError("Invalid excited state population " +
raise NoiseError("Invalid excited state population " +
"({} < 0).".format(excited_state_population))
if excited_state_population > 1:
raise AerNoiseError("Invalid excited state population " +
raise NoiseError("Invalid excited state population " +
"({} > 1).".format(excited_state_population))
c0 = np.sqrt(1 - excited_state_population)
c1 = np.sqrt(excited_state_population)

View File

@ -11,9 +11,9 @@ Noise model class for Qiskit Aer simulators.
import logging
from .aernoiseerror import AerNoiseError
from .quantum_error import QuantumError
from .readout_error import ReadoutError
from .noiseerror import NoiseError
from .errors.quantum_error import QuantumError
from .errors.readout_error import ReadoutError
logger = logging.getLogger(__name__)
@ -62,14 +62,14 @@ class NoiseModel:
operations (list[str]): the operations error applies to.
Raises:
AerNoiseError: if the input operations are not valid.
NoiseError: if the input operations are not valid.
"""
if isinstance(operations, str):
operations = [operations]
for op in operations:
if not isinstance(op, str):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
# Add X-90 based gate to noisy gates
self._noise_instructions.add(op)
self._x90_gates = operations
@ -83,7 +83,7 @@ class NoiseModel:
operations (str, list[str]): the operations error applies to.
Raises:
AerNoiseError: if the input parameters are invalid.
NoiseError: if the input parameters are invalid.
Additional Information:
If the error object is ideal it will not be added to the model.
@ -97,9 +97,9 @@ class NoiseModel:
try:
error = QuantumError(error)
except:
raise AerNoiseError("Input is not a valid quantum error.")
raise NoiseError("Input is not a valid quantum error.")
if not isinstance(operations, (list, tuple)):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
# Check if error is ideal and if so don't add to the noise model
if error.ideal():
@ -108,7 +108,7 @@ class NoiseModel:
# Add operations
for op in operations:
if not isinstance(op, str):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
self._check_number_of_qubits(error, op)
if op in self._default_quantum_errors:
logger.warning("WARNING: all-qubit error already exists for " +
@ -135,7 +135,7 @@ class NoiseModel:
qubits (list[int]): qubits operation error applies to.
Raises:
AerNoiseError: if the input parameters are invalid.
NoiseError: if the input parameters are invalid.
Additional Information:
If the error object is ideal it will not be added to the model.
@ -150,11 +150,11 @@ class NoiseModel:
try:
error = QuantumError(error)
except:
raise AerNoiseError("Input is not a valid quantum error.")
raise NoiseError("Input is not a valid quantum error.")
if not isinstance(qubits, (list, tuple)):
raise AerNoiseError("Qubits must be a list of integers.")
raise NoiseError("Qubits must be a list of integers.")
if not isinstance(operations, (list, tuple)):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
# Check if error is ideal and if so don't add to the noise model
if error.ideal():
@ -163,7 +163,7 @@ class NoiseModel:
# Add operations
for op in operations:
if not isinstance(op, str):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
# Check number of qubits is correct for standard operations
self._check_number_of_qubits(error, op)
if op in self._local_quantum_errors:
@ -174,7 +174,7 @@ class NoiseModel:
# Convert qubits list to hashable string
qubits_str = self._qubits2str(qubits)
if error.number_of_qubits != len(qubits):
raise AerNoiseError("Number of qubits ({}) does not match".format(len(qubits)) +
raise NoiseError("Number of qubits ({}) does not match".format(len(qubits)) +
" the error size ({})".format(error.number_of_qubits))
if qubits_str in qubit_dict:
logger.warning("WARNING: quantum error already exists for " +
@ -206,7 +206,7 @@ class NoiseModel:
should be applied to if different
to the operation qubits.
Raises:
AerNoiseError: if the input parameters are invalid.
NoiseError: if the input parameters are invalid.
Additional Information:
If the error object is ideal it will not be added to the model.
@ -221,13 +221,13 @@ class NoiseModel:
try:
error = QuantumError(error)
except:
raise AerNoiseError("Input is not a valid quantum error.")
raise NoiseError("Input is not a valid quantum error.")
if not isinstance(qubits, (list, tuple)):
raise AerNoiseError("Qubits must be a list of integers.")
raise NoiseError("Qubits must be a list of integers.")
if not isinstance(noise_qubits, (list, tuple)):
raise AerNoiseError("Noise qubits must be a list of integers.")
raise NoiseError("Noise qubits must be a list of integers.")
if not isinstance(operations, (list, tuple)):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
# Check if error is ideal and if so don't add to the noise model
if error.ideal():
@ -236,7 +236,7 @@ class NoiseModel:
# Add operations
for op in operations:
if not isinstance(op, str):
raise AerNoiseError("Qobj invalid operations.")
raise NoiseError("Qobj invalid operations.")
if op in self._nonlocal_quantum_errors:
qubit_dict = self._nonlocal_quantum_errors[op]
else:
@ -261,7 +261,7 @@ class NoiseModel:
error (ReadoutError): the quantum error object.
Raises:
AerNoiseError: if the input parameters are invalid.
NoiseError: if the input parameters are invalid.
Additional Information:
If the error object is ideal it will not be added to the model.
@ -272,7 +272,7 @@ class NoiseModel:
try:
error = ReadoutError(error)
except:
raise AerNoiseError("Input is not a valid readout error.")
raise NoiseError("Input is not a valid readout error.")
# Check if error is ideal and if so don't add to the noise model
if error.ideal():
@ -280,7 +280,7 @@ class NoiseModel:
# Check number of qubits is correct for standard operations
if error.number_of_qubits != 1:
raise AerNoiseError("All-qubit readout errors must defined as single-qubit errors.")
raise NoiseError("All-qubit readout errors must defined as single-qubit errors.")
if self._default_readout_error is not None:
logger.warning("WARNING: all-qubit readout error already exists, " +
"overriding with new readout error.")
@ -303,7 +303,7 @@ class NoiseModel:
qubits (list[int]): qubits operation error applies to.
Raises:
AerNoiseError: if the input parameters are invalid.
NoiseError: if the input parameters are invalid.
Additional Information:
If the error object is ideal it will not be added to the model.
@ -314,9 +314,9 @@ class NoiseModel:
try:
error = ReadoutError(error)
except:
raise AerNoiseError("Input is not a valid readout error.")
raise NoiseError("Input is not a valid readout error.")
if not isinstance(qubits, (list, tuple)):
raise AerNoiseError("Qubits must be a list of integers.")
raise NoiseError("Qubits must be a list of integers.")
# Check if error is ideal and if so don't add to the noise model
if error.ideal():
@ -326,7 +326,7 @@ class NoiseModel:
qubits_str = self._qubits2str(qubits)
# Check error matches qubit size
if error.number_of_qubits != len(qubits):
raise AerNoiseError("Number of qubits ({}) does not match".format(len(qubits)) +
raise NoiseError("Number of qubits ({}) does not match".format(len(qubits)) +
" the readout error size ({})".format(error.number_of_qubits))
# Check if we are overriding a previous error
if qubits_str in self._local_readout_errors:
@ -500,7 +500,7 @@ class NoiseModel:
noise_model.add_all_qubit_readout_error(roerror)
# Invalid error type
else:
raise AerNoiseError("Invalid error type: {}".format(error_type))
raise NoiseError("Invalid error type: {}".format(error_type))
return noise_model
def _check_number_of_qubits(self, error, operation):
@ -512,7 +512,7 @@ class NoiseModel:
operation (str): qobj operation strings to apply error to.
Raises:
AerNoiseError: If operation and error qubit number do not match.
NoiseError: If operation and error qubit number do not match.
"""
def error_message(gate_qubits):
msg = "{} qubit QuantumError".format(error.number_of_qubits) + \
@ -520,11 +520,11 @@ class NoiseModel:
" operation \"{}\".".format(operation)
return msg
if operation in self._1qubit_operations and error.number_of_qubits != 1:
raise AerNoiseError(error_message(1))
raise NoiseError(error_message(1))
if operation in self._2qubit_operations and error.number_of_qubits != 2:
raise AerNoiseError(error_message(2))
raise NoiseError(error_message(2))
if operation in self._3qubit_operations and error.number_of_qubits != 3:
raise AerNoiseError(error_message(3))
raise NoiseError(error_message(3))
def _qubits2str(self, qubits):
"""Convert qubits list to comma seperated qubits string."""

View File

@ -6,13 +6,13 @@
# the LICENSE.txt file in the root directory of this source tree.
"""
Exception for errors raised by Qiskit Aer.
Exception for errors raised by Qiskit Aer noise module.
"""
from qiskit import QISKitError
from qiskit.qiskiterror import QiskitError
class AerNoiseError(QISKitError):
class NoiseError(QiskitError):
"""Class for errors raised in qiskit_aer.noise package."""
def __init__(self, *message):

View File

@ -14,90 +14,56 @@ IS ADDED TO QISKIT TERRA. THEY WILL NOT BE SUPPORTED AFTER THAT.
import copy
import numpy as np
from qiskit.qobj import QobjItem
from qiskit.qobj import QobjInstruction
def qobj_append_item(qobj, exp_index, item):
"""Append a QobjItem to a Qobj experiment.
def append_instr(qobj, exp_index, instruction):
"""Append a QobjInstruction to a QobjExperiment.
Args:
qobj (Qobj): a Qobj object
exp_index (int): The index of the experiment in the qobj
item (QobjItem): The Qobj item to insert
qobj (Qobj): a Qobj object.
exp_index (int): The index of the experiment in the qobj.
instruction (QobjInstruction): instruction to insert.
"""
qobj.experiments[exp_index].instructions.append(item)
qobj.experiments[exp_index].instructions.append(instruction)
return qobj
def qobj_insert_item(qobj, exp_index, item, pos):
"""Insert a QobjItem into a Qobj experiment.
def insert_instr(qobj, exp_index, item, pos):
"""Insert a QobjInstruction into a QobjExperiment.
Args:
qobj (Qobj): a Qobj object
exp_index (int): The index of the experiment in the qobj
item (QobjItem): The Qobj item to insert
exp_index (int): The index of the experiment in the qobj.
instruction(QobjInstruction): instruction to insert.
pos (int): the position to insert the item.
"""
qobj.experiments[exp_index].instructions.insert(pos, item)
return qobj
def qobj_get_item_positions(qobj, exp_index, name):
"""Return all locations of QobjItem in a Qobj experiment.
def get_instr_pos(qobj, exp_index, name):
"""Return all locations of QobjInstruction in a Qobj experiment.
The return list is sorted in reverse order so iterating over it
to insert new items will work as expected.
Args:
qobj (Qobj): a Qobj object
exp_index (int): The index of the experiment in the qobj
name (str): QobjItem name to find
name (str): QobjInstruction name to find
Returns:
list[int]: A list of positions where the QobjItem is located.
list[int]: A list of positions where the QobjInstruction is located.
"""
# Check only the name string of the item
return [i for i, val in enumerate(qobj.experiments[exp_index].instructions)
if val.name == name]
positions = [i for i, val in enumerate(qobj.experiments[exp_index].instructions)
if val.name == name]
return positions
def qobj_get_specific_item_positions(qobj, exp_index, item):
"""Return all locations of QobjItem in a Qobj experiment.
Args:
qobj (Qobj): a Qobj object
exp_index (int): The index of the experiment in the qobj
item (QobjItem): The item to find
Returns:
list[int]: A list of positions where the QobjItem is located.
"""
return [i for i, val in enumerate(qobj.experiments[exp_index].instructions)
if val == item]
def qobj_insert_snapshots_after_barriers(qobj, snapshot):
"""Insert a snapshot instruction after each barrier in qobj.
The label of the input snapshot will be appended with "i" where
"i" ranges from 0 to the 1 - number of barriers.
Args:
snapshot (QobjItem): a snapshot instruction.
Additional Information:
"""
if snapshot.name != "snapshot":
raise ValueError("Invalid snapshot instruction")
label = snapshot.label
for exp_index in range(len(qobj.experiments)):
positions = qobj_get_item_positions(qobj, exp_index, "barrier")
for i, pos in reversed(list(enumerate(positions))):
item = copy.copy(snapshot)
item.label = label + "{}".format(i)
qobj_insert_item(qobj, exp_index, item, pos)
return qobj
def qobj_unitary_item(mat, qubits, label=None):
"""Create a unitary gate qobj item.
def unitary_instr(mat, qubits, label=None):
"""Create a unitary gate QobjInstruction.
Args:
mat (matrix_like): an n-qubit unitary matrix
@ -105,7 +71,7 @@ def qobj_unitary_item(mat, qubits, label=None):
label (str): optional string label for the untiary matrix
Returns:
QobjItem: The qobj item for the unitary instruction.
QobjInstruction: The qobj item for the unitary instruction.
Raises:
ValueError: if the input matrix is not unitary
@ -131,10 +97,38 @@ def qobj_unitary_item(mat, qubits, label=None):
"params": np.array(mat, dtype=complex)}
if label is not None:
instruction["label"] = str(label)
return QobjItem(**instruction)
return QobjInstruction(**instruction)
def qobj_snapshot_item(snapshot_type, label, qubits=None, params=None):
def measure_instr(qubits, memory, registers=None):
"""Create a multi-qubit measure instruction"""
if len(qubits) != len(memory):
raise ValueError("Number of qubits does not match number of memory")
if registers is None:
return QobjInstruction(name='measure', qubits=qubits, memory=memory)
# Case where we also measure to registers
if len(qubits) != len(registers):
raise ValueError("Number of qubits does not match number of registers")
return QobjInstruction(name='measure', qubits=qubits, memory=memory,
register=registers)
def reset_instr(qubits):
"""Create a multi-qubit reset instruction"""
return QobjInstruction(name='reset', qubits=qubits)
def barrier_instr(num_qubits):
"""Create a barrier QobjInstruction."""
return QobjInstruction(name='barrier', qubits=list(range(num_qubits)))
def iden_instr(qubit):
"""Create a barrier QobjInstruction."""
return QobjInstruction(name='id', qubits=[qubit])
def snapshot_instr(snapshot_type, label, qubits=None, params=None):
"""Create a snapshot qobj item.
Args:
@ -145,7 +139,7 @@ def qobj_snapshot_item(snapshot_type, label, qubits=None, params=None):
See additional information.
Returns:
QobjItem: The qobj item for the snapshot instruction.
QobjInstruction: The qobj item for the snapshot instruction.
Additional Information:
@ -184,32 +178,28 @@ def qobj_snapshot_item(snapshot_type, label, qubits=None, params=None):
snap["name"] = "expval_matrix"
snap["params"] = [[1.0, qubits, params]]
# TODO: implicit conversion for Pauli expval params
return QobjItem(**snap)
return QobjInstruction(**snap)
def qobj_measure_item(qubits, memory, registers=None):
"""Create a multi-qubit measure instruction"""
if len(qubits) != len(memory):
raise ValueError("Number of qubits does not match number of memory")
if registers is None:
return QobjItem(name='measure', qubits=qubits, memory=memory)
# Case where we also measure to registers
if len(qubits) != len(registers):
raise ValueError("Number of qubits does not match number of registers")
return QobjItem(name='measure', qubits=qubits, memory=memory,
register=registers)
def insert_snapshots_after_barriers(qobj, snapshot):
"""Insert a snapshot instruction after each barrier in qobj.
The label of the input snapshot will be appended with "i" where
"i" ranges from 0 to the 1 - number of barriers.
def qobj_reset_item(qubits):
"""Create a multi-qubit reset instruction"""
return QobjItem(name='reset', qubits=qubits)
Args:
qobj (Qobj): a qobj to insert snapshots into
snapshot (QobjInstruction): a snapshot instruction.
def qobj_barrier_item(num_qubits):
"""Create a barrier QobjItem."""
return QobjItem(name='barrier', qubits=list(range(num_qubits)))
def qobj_iden_item(qubit):
"""Create a barrier QobjItem."""
return QobjItem(name='id', qubits=[qubit])
Additional Information:
"""
if snapshot.name != "snapshot":
raise ValueError("Invalid snapshot instruction")
label = snapshot.label
for exp_index in range(len(qobj.experiments)):
positions = get_instr_pos(qobj, exp_index, "barrier")
for i, pos in reversed(list(enumerate(positions))):
item = copy.copy(snapshot)
item.label = label + "{}".format(i)
insert_instr(qobj, exp_index, item, pos)
return qobj

View File

@ -54,16 +54,45 @@ namespace Base {
// It manages execution of all the circuits in a QOBJ, parallelization,
// noise sampling from a noise model, and circuit optimizations.
// Parallelization:
// Parallel execution uses the OpenMP library. It may happen at three
// levels:
// 1. Parallel execution of circuits in a QOBJ
// 2. Parallel execution of shots in a Circuit
// 3. Parallelization used by the State class for performing gates.
// Options 1 and 2 are mutually exclusive: enabling circuit parallelization
// disables shot parallelization and vice versa. Option 3 is available for
// both cases but conservatively limits the number of threads since these
// are subthreads spawned by the higher level threads.
/**************************************************************************
* ---------------
* Parallelization
* ---------------
* Parallel execution uses the OpenMP library. It may happen at three levels:
*
* 1. Parallel execution of circuits in a QOBJ
* 2. Parallel execution of shots in a Circuit
* 3. Parallelization used by the State class for performing gates.
*
* Options 1 and 2 are mutually exclusive: enabling circuit parallelization
* disables shot parallelization. Option 3 is available for both cases but
* conservatively limits the number of threads since these are subthreads
* spawned by the higher level threads. If no parallelization is used for
* 1 and 2, all available threads will be used for 3.
*
* -------------------------
* Config settings:
*
* - "noise_model" (json): A noise model to use for simulation [Default: null]
* - "max_parallel_threads" (int): Set the maximum OpenMP threads that may
* be used across all levels of parallelization. Set to 0 for maximum
* available. [Default : 0]
* - "max_parallel_experiments" (int): Set number of circuits that may be
* executed in parallel. Set to 0 to use the number of max parallel
* threads [Default: 1]
* - "max_parallel_shots" (int): Set number of shots that maybe be executed
* in parallel for each circuit. Sset to 0 to use the number of max
* parallel threads [Default: 1].
*
* Config settings from Data class:
*
* - "counts" (bool): Return counts objecy in circuit data [Default: True]
* - "snapshots" (bool): Return snapshots object in circuit data [Default: True]
* - "memory" (bool): Return memory array in circuit data [Default: False]
* - "register" (bool): Return register array in circuit data [Default: False]
* - "noise_model" (json): A noise model JSON dictionary for the simulator.
* [Default: null]
**************************************************************************/
class Controller {
public:
@ -84,21 +113,6 @@ public:
// Load Controller, State and Data config from a JSON
// config settings will be passed to the State and Data classes
// Allowed Controller config options:
// - "noise_model": NoiseModel JSON
// A noise model JSON dictionary for the simulator.
// - "max_threads": int
// Set the maximum OpenMP threads that may be used across all levels
// of parallelization. Set to -1 for maximum available (Default: -1)
// - "max_threads_circuit": int
// Set the maximum OpenMP threads that may be used for parallel
// circuit evaluation. Set to -1 for maximum available (Default: 1)
// - "max_threads_shot": int
// Set the maximum OpenMP threads that may be used for parallel
// shot evaluation. Set to -1 for maximum available (Default: 1)
// - "max_threads_state": int
// Set the maximum OpenMP threads that may be used by the State
// class. Set to -1 for maximum available (Default: -1)
virtual void set_config(const json_t &config);
// Clear the current config
@ -147,13 +161,11 @@ protected:
int available_threads_ = 1;
// The maximum number of threads to use for various levels of parallelization
int max_threads_total_ = -1;
int max_threads_circuit_ = 1; // -1 for maximum available
int max_threads_shot_ = 1; // -1 for maximum available
int max_threads_state_ = -1; // -1 for maximum available
// set to 0 for maximum available
int max_threads_total_;
int max_threads_circuit_;
int max_threads_shot_;
int max_threads_state_;
};
@ -167,18 +179,22 @@ protected:
//-------------------------------------------------------------------------
void Controller::set_config(const json_t &config) {
// Save config for passing to State and Data classes
config_ = config;
// Add noise model
// Load noise model
if (JSON::check_key("noise_model", config))
noise_model_ = Noise::NoiseModel(config["noise_model"]);
// Default: max_threads = -1 (all available threads)
JSON::get_value(max_threads_total_, "max_threads", config);
// Default: max_threads_circuit = 1
JSON::get_value(max_threads_circuit_, "max_threads_circuit", config);
// Default: max_threads_shot = 1
JSON::get_value(max_threads_shot_, "max_threads_shot", config);
// Default: max_threads_state = -1 (all available threads)
JSON::get_value(max_threads_shot_, "max_threads_state", config);
// Load OpenMP maximum thread settings
JSON::get_value(max_threads_total_, "max_parallel_threads", config);
JSON::get_value(max_threads_shot_, "max_parallel_shots", config);
JSON::get_value(max_threads_circuit_, "max_parallel_experiments", config);
// Prevent using both parallel circuits and parallel shots
// with preference given to parallel circuit execution
if (max_threads_circuit_ > 1)
max_threads_shot_ = 1;
}
void Controller::clear_config() {
@ -188,10 +204,10 @@ void Controller::clear_config() {
}
void Controller::set_threads_default() {
max_threads_total_ = -1;
max_threads_total_ = 0;
max_threads_state_ = 0;
max_threads_circuit_ = 1;
max_threads_shot_ = 1;
max_threads_state_ = -1;
}
@ -204,10 +220,15 @@ json_t Controller::execute(const json_t &qobj_js) {
// Start QOBJ timer
auto timer_start = myclock_t::now();
// Look for config and load
if (JSON::check_key("config", qobj_js)) {
set_config(qobj_js["config"]);
}
// Generate empty return JSON that matches Result spec
json_t result;
result["qobj_id"] = nullptr;
result["success"] = true;
result["status"] = nullptr;
result["backend_name"] = nullptr;
result["backend_version"] = nullptr;
result["date"] = nullptr;
result["job_id"] = nullptr;
// Load QOBJ in a try block so we can catch parsing errors and still return
// a valid JSON output containing the error message.
@ -216,21 +237,23 @@ json_t Controller::execute(const json_t &qobj_js) {
qobj.load_qobj_from_json(qobj_js);
}
catch (std::exception &e) {
json_t ret;
ret["qobj_id"] = "ERROR";
ret["success"] = false;
ret["status"] = std::string("ERROR: Failed to load qobj: ") + e.what();
ret["backend_name"] = nullptr;
ret["backend_version"] = nullptr;
ret["date"] = nullptr;
ret["job_id"] = nullptr;
return ret; // qobj was invalid, return valid output containing error message
// qobj was invalid, return valid output containing error message
result["success"] = false;
result["status"] = std::string("ERROR: Failed to load qobj: ") + e.what();
return result;
}
// Get QOBJ id and pass through header to result
result["qobj_id"] = qobj.id;
if (!qobj.header.empty())
result["header"] = qobj.header;
// Check for config
if (JSON::check_key("config", qobj_js)) {
set_config(qobj_js["config"]);
}
// Qobj was loaded successfully, now we proceed
json_t ret;
bool all_success = true;
try {
int num_circuits = qobj.circuits.size();
@ -253,65 +276,59 @@ json_t Controller::execute(const json_t &qobj_js) {
available_threads_ /= num_threads_circuit;
// Add thread metatdata to output
ret["metadata"]["omp_enabled"] = true;
ret["metadata"]["omp_available_threads"] = omp_nthreads;
ret["metadata"]["omp_circuit_threads"] = num_threads_circuit;
result["metadata"]["omp_enabled"] = true;
result["metadata"]["omp_available_threads"] = omp_nthreads;
result["metadata"]["omp_circuit_threads"] = num_threads_circuit;
#else
ret["metadata"]["omp_enabled"] = false;
result["metadata"]["omp_enabled"] = false;
#endif
// Initialize container to store parallel circuit output
ret["results"] = std::vector<json_t>(num_circuits);
result["results"] = std::vector<json_t>(num_circuits);
if (num_threads_circuit > 1) {
// Parallel circuit execution
#pragma omp parallel for if (num_threads_circuit > 1) num_threads(num_threads_circuit)
for (int j = 0; j < num_circuits; ++j) {
ret["results"][j] = execute_circuit(qobj.circuits[j]);
result["results"][j] = execute_circuit(qobj.circuits[j]);
}
} else {
// Serial circuit execution
for (int j = 0; j < num_circuits; ++j) {
ret["results"][j] = execute_circuit(qobj.circuits[j]);
result["results"][j] = execute_circuit(qobj.circuits[j]);
}
}
// check success
for (const auto& res: ret["results"]) {
all_success &= res["success"].get<bool>();
for (const auto& experiment: result["results"]) {
if (experiment["success"].get<bool>() == false) {
result["success"] = false;
break;
}
}
// Add success data
ret["success"] = all_success;
ret["status"] = std::string("COMPLETED");
ret["qobj_id"] = qobj.id;
if (!qobj.header.empty())
ret["header"] = qobj.header;
ret["backend_name"] = nullptr;
ret["backend_version"] = nullptr;
ret["date"] = nullptr;
ret["job_id"] = nullptr;
// Set status to completed
result["status"] = std::string("COMPLETED");
// Stop the timer and add total timing data
auto timer_stop = myclock_t::now();
ret["metadata"]["time_taken"] = std::chrono::duration<double>(timer_stop - timer_start).count();
result["metadata"]["time_taken"] = std::chrono::duration<double>(timer_stop - timer_start).count();
}
// If execution failed return valid output reporting error
catch (std::exception &e) {
ret["success"] = false;
ret["status"] = std::string("ERROR: ") + e.what();
result["success"] = false;
result["status"] = std::string("ERROR: ") + e.what();
}
return ret;
return result;
}
json_t Controller::execute_circuit(Circuit &circ) {
// Start individual circuit timer
auto timer_start = myclock_t::now(); // state circuit timer
// Initialize circuit json return
json_t ret;
json_t result;
// Execute in try block so we can catch errors and return the error message
// for individual circuit failures.
@ -337,13 +354,13 @@ json_t Controller::execute_circuit(Circuit &circ) {
: std::min<int>({available_threads_ , max_threads_total_, max_threads_state_});
// Add thread information to result metadata
ret["metadata"]["omp_shot_threads"] = num_threads_shot;
ret["metadata"]["omp_state_threads"] = num_threads_state;
result["metadata"]["omp_shot_threads"] = num_threads_shot;
result["metadata"]["omp_state_threads"] = num_threads_state;
#endif
// Single shot thread execution
if (num_threads_shot <= 1) {
ret["data"] = run_circuit(circ, circ.shots, circ.seed, num_threads_state);
result["data"] = run_circuit(circ, circ.shots, circ.seed, num_threads_state);
// Parallel shot thread execution
} else {
// Calculate shots per thread
@ -351,7 +368,10 @@ json_t Controller::execute_circuit(Circuit &circ) {
for (int j = 0; j < num_threads_shot; ++j) {
subshots.push_back(circ.shots / num_threads_shot);
}
subshots[0] += (circ.shots % num_threads_shot);
// If shots is not perfectly divisible by threads, assign the remaineder
for (int j=0; j < (circ.shots % num_threads_shot); ++j) {
subshots[j] += 1;
}
// Vector to store parallel thread output data
std::vector<OutputData> data(num_threads_shot);
@ -364,27 +384,27 @@ json_t Controller::execute_circuit(Circuit &circ) {
data[0].combine(data[j]);
}
// Update output
ret["data"] = data[0];
result["data"] = data[0];
}
// Report success
ret["success"] = true;
ret["status"] = std::string("DONE");
result["success"] = true;
result["status"] = std::string("DONE");
// Pass through circuit header and add metadata
ret["header"] = circ.header;
ret["shots"] = circ.shots;
ret["seed"] = circ.seed;
result["header"] = circ.header;
result["shots"] = circ.shots;
result["seed"] = circ.seed;
// Add timer data
auto timer_stop = myclock_t::now(); // stop timer
double time_taken = std::chrono::duration<double>(timer_stop - timer_start).count();
ret["time_taken"] = time_taken;
result["time_taken"] = time_taken;
}
// If an exception occurs during execution, catch it and pass it to the output
catch (std::exception &e) {
ret["success"] = false;
ret["status"] = std::string("ERROR: ") + e.what();
result["success"] = false;
result["status"] = std::string("ERROR: ") + e.what();
}
return ret;
return result;
}
//-------------------------------------------------------------------------

View File

@ -18,6 +18,15 @@ namespace AER {
// Output data class for Qiskit-Aer
//============================================================================
/**************************************************************************
* Data config options:
*
* - "counts" (bool): Return counts objecy in circuit data [Default: True]
* - "snapshots" (bool): Return snapshots object in circuit data [Default: True]
* - "memory" (bool): Return memory array in circuit data [Default: False]
* - "register" (bool): Return register array in circuit data [Default: False]
**************************************************************************/
class OutputData {
public:
//----------------------------------------------------------------

View File

@ -428,9 +428,11 @@ Op json_to_op_noise_switch(const json_t &js) {
Op json_to_op_snapshot(const json_t &js) {
std::string type;
JSON::get_value(type, "type", js);
if (type == "expval_pauli")
if (type == "expectation_value_pauli" ||
type == "expectation_value_pauli_with_variance")
return json_to_op_snapshot_pauli(js);
if (type == "expval_matrix")
if (type == "expectation_value_matrix" ||
type == "expectation_value_matrix_with_variance")
return json_to_op_snapshot_matrix(js);
// Default snapshot: has "type", "label", "qubits"
return json_to_op_snapshot_default(js);
@ -455,8 +457,7 @@ Op json_to_op_snapshot_default(const json_t &js) {
Op json_to_op_snapshot_pauli(const json_t &js) {
// Load default snapshot parameters
Op op = json_to_op_snapshot_default(js);
// override name for depreciated "pauli_observable"
op.name = "expval_pauli";
// Check qubits are valid
check_empty_qubits(op);
check_duplicate_qubits(op);
@ -481,7 +482,8 @@ Op json_to_op_snapshot_pauli(const json_t &js) {
if (std::abs(coeff) > threshold) {
std::string pauli = comp[1];
if (pauli.size() != op.qubits.size()) {
throw std::invalid_argument("Invalid Pauli snapshot (Pauli label does not match qubit number.).");
throw std::invalid_argument(std::string("Invalid Pauli expectation value snapshot ") +
"(Pauli label does not match qubit number.).");
}
// make tuple and add to components
op.params_expval_pauli.push_back(std::make_pair(coeff, pauli));
@ -497,8 +499,6 @@ Op json_to_op_snapshot_pauli(const json_t &js) {
Op json_to_op_snapshot_matrix(const json_t &js) {
// Load default snapshot parameters
Op op = json_to_op_snapshot_default(js);
// override name for depreciated "pauli_observable"
op.name = "expval_matrix";
const auto threshold = 1e-10; // drop small components
// Get matrix operator components
@ -538,7 +538,8 @@ Op json_to_op_snapshot_matrix(const json_t &js) {
}
} // end component loop
} else {
throw std::invalid_argument("Invalid matrix snapshot (\"params\" field missing).");
throw std::invalid_argument(std::string("Invalid matrix expectation value snapshot ") +
"(\"params\" field missing).");
}
return op;
}

View File

@ -18,6 +18,43 @@ namespace Simulator {
// QasmController class
//=========================================================================
/**************************************************************************
* Config settings:
*
* From QubitVector::State class
*
* - "initial_statevector" (json complex vector): Use a custom initial
* statevector for the simulation [Default: null].
* - "chop_threshold" (double): Threshold for truncating small values to
* zero in result data [Default: 1e-15]
* - "statevector_parallel_threshold" (int): Threshold that number of qubits
* must be greater than to enable OpenMP parallelization at State
* level [Default: 13]
* - "statevector_sample_measure_opt" (int): Threshold that number of qubits
* must be greater than to enable indexing optimization during
* measure sampling [Default: 10]
* - "statevector_hpc_gate_opt" (bool): Enable large qubit gate optimizations.
* [Default: False]
*
* From BaseController Class
*
* - "noise_model" (json): A noise model to use for simulation [Default: null]
* - "max_parallel_threads" (int): Set the maximum OpenMP threads that may
* be used across all levels of parallelization. Set to 0 for maximum
* available. [Default : 0]
* - "max_parallel_experiments" (int): Set number of circuits that may be
* executed in parallel. Set to 0 to use the number of max parallel
* threads [Default: 1]
* - "max_parallel_shots" (int): Set number of shots that maybe be executed
* in parallel for each circuit. Sset to 0 to use the number of max
* parallel threads [Default: 1].
* - "counts" (bool): Return counts objecy in circuit data [Default: True]
* - "snapshots" (bool): Return snapshots object in circuit data [Default: True]
* - "memory" (bool): Return memory array in circuit data [Default: False]
* - "register" (bool): Return register array in circuit data [Default: False]
*
**************************************************************************/
class QasmController : public Base::Controller {
public:
//-----------------------------------------------------------------------

View File

@ -181,7 +181,7 @@ protected:
// Config settings
//-----------------------------------------------------------------------
uint_t omp_threads_ = 1; // Disable multithreading by default
uint_t omp_threshold_ = 16; // Qubit threshold for multithreading when enabled
uint_t omp_threshold_ = 6; // Qubit threshold for multithreading when enabled
double json_chop_threshold_ = 0; // Threshold for choping small values
// in JSON serialization

View File

@ -18,6 +18,32 @@ namespace Simulator {
// UnitaryController class
//=========================================================================
/**************************************************************************
* Config settings:
*
* From QubitUnitary::State class
*
* - "initial_unitary" (json complex matrix): Use a custom initial unitary
* matrix for the simulation [Default: null].
* - "chop_threshold" (double): Threshold for truncating small values to
* zero in result data [Default: 1e-15]
* - "unitary_parallel_threshold" (int): Threshold that number of qubits
* must be greater than to enable OpenMP parallelization at State
* level [Default: 6]
*
* From BaseController Class
*
* - "max_parallel_threads" (int): Set the maximum OpenMP threads that may
* be used across all levels of parallelization. Set to 0 for maximum
* available. [Default : 0]
* - "max_parallel_experiments" (int): Set number of circuits that may be
* executed in parallel. Set to 0 to use the number of max parallel
* threads [Default: 1]
* - "snapshots" (bool): Return snapshots object in circuit data [Default: True]
*
**************************************************************************/
class UnitaryController : public Base::Controller {
public:
//-----------------------------------------------------------------------

View File

@ -23,7 +23,7 @@ namespace QubitUnitary {
// Allowed gates enum class
enum class Gates {
u0, u1, u2, u3, id, x, y, z, h, s, sdg, t, tdg, // single qubit
u1, u2, u3, id, x, y, z, h, s, sdg, t, tdg, // single qubit
cx, cz, swap, // two qubit
ccx // three qubit
};
@ -57,13 +57,13 @@ public:
// Return the set of qobj gate instruction names supported by the State
inline virtual stringset_t allowed_gates() const override {
return {"U", "CX", "u0", "u1", "u2", "u3", "cx", "cz", "swap",
return {"U", "CX", "u1", "u2", "u3", "cx", "cz", "swap",
"id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx"};
}
// Return the set of qobj snapshot types supported by the State
inline virtual stringset_t allowed_snapshots() const override {
return {"state", "unitary"};
return {"unitary"};
}
// Apply a sequence of operations by looping over list
@ -133,7 +133,7 @@ protected:
//-----------------------------------------------------------------------
// OpenMP qubit threshold
int omp_qubit_threshold_ = 7;
int omp_qubit_threshold_ = 6;
// Threshold for chopping small values to zero in JSON
double json_chop_threshold_ = 1e-15;
@ -160,7 +160,6 @@ const stringmap_t<Gates> State<statemat_t>::gateset_({
{"t", Gates::t}, // T-gate (sqrt(S))
{"tdg", Gates::tdg}, // Conjguate-transpose of T gate
// Waltz Gates
{"u0", Gates::u0}, // idle gate in multiples of X90
{"u1", Gates::u1}, // zero-X90 pulse waltz gate
{"u2", Gates::u2}, // single-X90 pulse waltz gate
{"u3", Gates::u3}, // two X90 pulse waltz gate
@ -220,7 +219,7 @@ uint_t State<statemat_t>::required_memory_mb(uint_t num_qubits,
template <class statemat_t>
void State<statemat_t>::set_config(const json_t &config) {
// Set OMP threshold for state update functions
JSON::get_value(omp_qubit_threshold_, "omp_qubit_threshold", config);
JSON::get_value(omp_qubit_threshold_, "unitary_parallel_threshold", config);
// Set threshold for truncating snapshots
JSON::get_value(json_chop_threshold_, "chop_threshold", config);
@ -303,8 +302,6 @@ void State<statemat_t>::apply_gate(const Operations::Op &op) {
case Gates::cz:
BaseState::qreg_.apply_cz(op.qubits[0], op.qubits[1]);
break;
case Gates::u0: // u0 = id in ideal State
break;
case Gates::id:
break;
case Gates::x:

View File

@ -248,9 +248,9 @@ protected:
// Config settings
//-----------------------------------------------------------------------
uint_t omp_threads_ = 1; // Disable multithreading by default
uint_t omp_threshold_ = 16; // Qubit threshold for multithreading when enabled
uint_t omp_threshold_ = 13; // Qubit threshold for multithreading when enabled
int sample_measure_index_size_ = 10; // Sample measure indexing qubit size
bool gate_opt_ = false; // enable large-qubit optimized gates
bool gate_opt_ = false; // enable large-qubit optimized gates
double json_chop_threshold_ = 0; // Threshold for choping small values
// in JSON serialization
//-----------------------------------------------------------------------

View File

@ -23,7 +23,7 @@ namespace QubitVector {
// Allowed gates enum class
enum class Gates {
u0, u1, u2, u3, id, x, y, z, h, s, sdg, t, tdg, // single qubit
u1, u2, u3, id, x, y, z, h, s, sdg, t, tdg, // single qubit
cx, cz, swap, // two qubit
ccx // three qubit
};
@ -69,14 +69,16 @@ public:
// Return the set of qobj gate instruction names supported by the State
inline virtual stringset_t allowed_gates() const override {
return {"U", "CX", "u0", "u1", "u2", "u3", "cx", "cz", "swap",
return {"U", "CX", "u1", "u2", "u3", "cx", "cz", "swap",
"id", "x", "y", "z", "h", "s", "sdg", "t", "tdg", "ccx"};
}
// Return the set of qobj snapshot types supported by the State
inline virtual stringset_t allowed_snapshots() const override {
return {"state", "statevector", "probabilities", "expval_pauli",
"expval_matrix", "memory", "register"};
return {"statevector", "memory", "register",
"probabilities", "probabilities_with_variance",
"expectation_value_pauli", "expectation_value_pauli_with_variance",
"expectation_value_matrix", "expectation_value_matrix_with_variance"};
}
// Apply a sequence of operations by looping over list
@ -100,8 +102,6 @@ public:
// Load the threshold for applying OpenMP parallelization
// if the controller/engine allows threads for it
// Config: {"omp_qubit_threshold": 14}
// TODO: Check optimal default value for a desktop i7 CPU
virtual void set_config(const json_t &config) override;
// Sample n-measurement outcomes without applying the measure operation
@ -228,6 +228,9 @@ protected:
// OpenMP qubit threshold
int omp_qubit_threshold_ = 14;
// QubitVector sample measure index size
int sample_measure_index_size_ = 10;
// Threshold for chopping small values to zero in JSON
double json_chop_threshold_ = 1e-15;
@ -257,7 +260,6 @@ const stringmap_t<Gates> State<statevec_t>::gateset_({
{"t", Gates::t}, // T-gate (sqrt(S))
{"tdg", Gates::tdg}, // Conjguate-transpose of T gate
// Waltz Gates
{"u0", Gates::u0}, // idle gate in multiples of X90
{"u1", Gates::u1}, // zero-X90 pulse waltz gate
{"u2", Gates::u2}, // single-X90 pulse waltz gate
{"u3", Gates::u3}, // two X90 pulse waltz gate
@ -275,13 +277,12 @@ const stringmap_t<Gates> State<statevec_t>::gateset_({
template <class statevec_t>
const stringmap_t<Snapshots> State<statevec_t>::snapshotset_({
{"statevector", Snapshots::statevector},
{"state", Snapshots::statevector},
{"probabilities", Snapshots::probs},
{"expval_pauli", Snapshots::expval_pauli},
{"expval_matrix", Snapshots::expval_matrix},
{"expectation_value_pauli", Snapshots::expval_pauli},
{"expectation_value_matrix", Snapshots::expval_matrix},
{"probabilities_with_variance", Snapshots::probs_var},
{"expval_pauli_with_variance", Snapshots::expval_pauli_var},
{"expval_matrix_with_variance", Snapshots::expval_matrix_var},
{"expectation_value_pauli_with_variance", Snapshots::expval_pauli_var},
{"expectation_value_matrix_with_variance", Snapshots::expval_matrix_var},
{"memory", Snapshots::cmemory},
{"register", Snapshots::cregister}
});
@ -355,17 +356,17 @@ void State<statevec_t>::set_config(const json_t &config) {
BaseState::qreg_.set_json_chop_threshold(json_chop_threshold_);
// Set OMP threshold for state update functions
JSON::get_value(omp_qubit_threshold_, "omp_qubit_threshold", config);
JSON::get_value(omp_qubit_threshold_, "statevector_parallel_threshold", config);
// Set the sample measure indexing size
int index_size;
if (JSON::get_value(index_size, "sample_measure_index_size", config)) {
if (JSON::get_value(index_size, "statevector_sample_measure_opt", config)) {
BaseState::qreg_.set_sample_measure_index_size(index_size);
};
// Enable sorted gate optimzations
bool gate_opt = false;
JSON::get_value(gate_opt, "gate_optimization", config);
JSON::get_value(gate_opt, "statevector_gate_opt", config);
if (gate_opt)
BaseState::qreg_.enable_gate_opt();
}
@ -620,8 +621,6 @@ void State<statevec_t>::apply_gate(const Operations::Op &op) {
case Gates::cz:
BaseState::qreg_.apply_cz(op.qubits[0], op.qubits[1]);
break;
case Gates::u0: // u0 = id in ideal State
break;
case Gates::id:
break;
case Gates::x:

View File

@ -18,6 +18,39 @@ namespace Simulator {
// StatevectorController class
//=========================================================================
/**************************************************************************
* Config settings:
*
* From QubitVector::State class
*
* - "initial_statevector" (json complex vector): Use a custom initial
* statevector for the simulation [Default: null].
* - "chop_threshold" (double): Threshold for truncating small values to
* zero in result data [Default: 1e-15]
* - "statevector_parallel_threshold" (int): Threshold that number of qubits
* must be greater than to enable OpenMP parallelization at State
* level [Default: 13]
* - "statevector_sample_measure_opt" (int): Threshold that number of qubits
* must be greater than to enable indexing optimization during
* measure sampling [Default: 10]
* - "statevector_hpc_gate_opt" (bool): Enable large qubit gate optimizations.
* [Default: False]
*
* From BaseController Class
*
* - "max_parallel_threads" (int): Set the maximum OpenMP threads that may
* be used across all levels of parallelization. Set to 0 for maximum
* available. [Default : 0]
* - "max_parallel_experiments" (int): Set number of circuits that may be
* executed in parallel. Set to 0 to use the number of max parallel
* threads [Default: 1]
* - "counts" (bool): Return counts objecy in circuit data [Default: True]
* - "snapshots" (bool): Return snapshots object in circuit data [Default: True]
* - "memory" (bool): Return memory array in circuit data [Default: False]
* - "register" (bool): Return register array in circuit data [Default: False]
*
**************************************************************************/
class StatevectorController : public Base::Controller {
public:
//-----------------------------------------------------------------------

View File

@ -6,7 +6,7 @@ import time
from multiprocessing import cpu_count
import qiskit
from qiskit import QISKitError
from qiskit import QiskitError
from qiskit import ClassicalRegister, QuantumCircuit
from qiskit_aer.backends.qasm_simulator import QasmSimulator
from qiskit_aer.noise import NoiseModel
@ -65,7 +65,7 @@ def benchmark_circuits(backend, circuits, shots=1):
number of circuits.
Raises:
QISKitError: If the simulation execution fails.
QiskitError: If the simulation execution fails.
"""
qobj = qiskit.compile(circuits, backend, shots=shots)
start_time = time.time()
@ -76,7 +76,7 @@ def benchmark_circuits(backend, circuits, shots=1):
else:
average_time = (end_time - start_time) / len(circuits)
if result.status != 'COMPLETED':
raise QISKitError("Simulation failed. Status: " + result.status)
raise QiskitError("Simulation failed. Status: " + result.status)
return average_time

View File

@ -5,17 +5,21 @@
# 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.
import test.terra.utils.common as common
import unittest
"""
NoiseModel class integration tests
"""
import unittest
from test.terra.utils import common
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
from qiskit import compile
from qiskit_aer.noise import NoiseModel, QuantumError
from qiskit_aer.backends import QasmSimulator
from qiskit_aer.noise import NoiseModel
from qiskit_aer.noise.errors.quantum_error import QuantumError
from qiskit_aer.noise.errors.standard_errors import pauli_error
from qiskit_aer.noise.errors.standard_errors import amplitude_damping_error
from qiskit_aer.utils.qobj_utils import qobj_measure_item
from qiskit_aer.utils.qobj_utils import qobj_append_item
from qiskit_aer.utils.qobj_utils import measure_instr
from qiskit_aer.utils.qobj_utils import append_instr
class TestNoise(common.QiskitAerTestCase):
@ -156,8 +160,8 @@ class TestNoise(common.QiskitAerTestCase):
qobj = compile([circuit], backend, shots=shots,
basis_gates=noise_model.basis_gates)
# Add measure to qobj
item = qobj_measure_item([0, 1], [0, 1])
qobj_append_item(qobj, 0, item)
item = measure_instr([0, 1], [0, 1])
append_instr(qobj, 0, item)
# Execute
result = backend.run(qobj, noise_model=noise_model).result()
self.is_completed(result)

View File

@ -9,6 +9,7 @@
QasmSimulator Integration Tests
"""
import unittest
from test.terra.utils import common
from test.terra.utils import ref_measure
from test.terra.utils import ref_reset
@ -18,12 +19,10 @@ from test.terra.utils import ref_2q_clifford
from test.terra.utils import ref_non_clifford
from test.terra.utils import ref_algorithms
from test.terra.utils import ref_unitary_gate
import unittest
from qiskit import execute
from qiskit_aer.backends import QasmSimulator
# TODO: Enable minimal basis (U,X) tests once bugs in terra are fixed
class TestQasmSimulator(common.QiskitAerTestCase):
"""QasmSimulator tests."""

View File

@ -5,16 +5,16 @@
# 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.
from test.terra.utils import common
"""
QuantumError class tests
"""
import unittest
from test.terra.utils import common
import numpy as np
from qiskit_aer.noise.noise_utils import standard_gate_unitary
from qiskit_aer.noise import QuantumError
from qiskit_aer.noise.aernoiseerror import AerNoiseError
# TODO:
# * Test compose error for different qubit number
from qiskit_aer.noise.noiseerror import NoiseError
from qiskit_aer.noise.errors.quantum_error import QuantumError
from qiskit_aer.noise.errors.errorutils import standard_gate_unitary
class TestQuantumError(common.QiskitAerTestCase):
@ -81,38 +81,38 @@ class TestQuantumError(common.QiskitAerTestCase):
"""Test exception is raised for negative probabilities."""
noise_ops = [([{"name": "id", "qubits": [0]}], 1.1),
([{"name": "x", "qubits": [0]}], -0.1)]
self.assertRaises(AerNoiseError, lambda: QuantumError(noise_ops))
self.assertRaises(NoiseError, lambda: QuantumError(noise_ops))
def test_raise_probabilities_normalized_qobj(self):
"""Test exception is raised for qobj probabilities greater than 1."""
noise_ops = [([{"name": "id", "qubits": [0]}], 0.9),
([{"name": "x", "qubits": [0]}], 0.2)]
self.assertRaises(AerNoiseError, lambda: QuantumError(noise_ops))
self.assertRaises(NoiseError, lambda: QuantumError(noise_ops))
def test_raise_probabilities_normalized_unitary_kraus(self):
"""Test exception is raised for unitary kraus probs greater than 1."""
A0 = np.sqrt(0.9) * np.eye(2)
A1 = np.sqrt(0.2) * np.diag([1, -1])
self.assertRaises(AerNoiseError, lambda: QuantumError([A0, A1]))
self.assertRaises(NoiseError, lambda: QuantumError([A0, A1]))
def test_raise_probabilities_normalized_nonunitary_kraus(self):
"""Test exception is raised for non-unitary kraus probs greater than 1."""
A0 = np.sqrt(0.9) * np.array([[1, 0], [0, np.sqrt(1 - 0.3)]])
A1 = np.sqrt(0.2) * np.array([[0, np.sqrt(0.3)], [0, 0]])
self.assertRaises(AerNoiseError, lambda: QuantumError([A0, A1]))
self.assertRaises(NoiseError, lambda: QuantumError([A0, A1]))
def test_raise_non_cptp_kraus(self):
"""Test exception is raised for non-CPTP input."""
A0 = np.array([[1, 0], [0, np.sqrt(1 - 0.3)]])
A1 = np.array([[0, 0], [np.sqrt(0.3), 0]])
self.assertRaises(AerNoiseError, lambda: QuantumError([A0, A1]))
self.assertRaises(AerNoiseError, lambda: QuantumError([A0]))
self.assertRaises(NoiseError, lambda: QuantumError([A0, A1]))
self.assertRaises(NoiseError, lambda: QuantumError([A0]))
def test_raise_non_multiqubit_kraus(self):
"""Test exception is raised for non-multiqubit input."""
A0 = np.sqrt(0.5) * np.diag([1, 1, 1])
A1 = np.sqrt(0.5) * np.diag([1, 1, -1])
self.assertRaises(AerNoiseError, lambda: QuantumError([A0, A1]))
self.assertRaises(NoiseError, lambda: QuantumError([A0, A1]))
def test_pauli_conversion_standard_gates(self):
"""Test conversion of Pauli channel kraus to gates"""
@ -246,8 +246,8 @@ class TestQuantumError(common.QiskitAerTestCase):
"""Test composing incompatible errors raises exception"""
error0 = QuantumError([np.diag([1, 1, 1, -1])]) # 2-qubit coherent error
error1 = QuantumError([np.diag([1, -1])]) # 1-qubit coherent error
self.assertRaises(AerNoiseError, lambda: error0.compose(error1))
self.assertRaises(AerNoiseError, lambda: error1.compose(error0))
self.assertRaises(NoiseError, lambda: error0.compose(error1))
self.assertRaises(NoiseError, lambda: error1.compose(error0))
def test_compose_both_kraus(self):
"""Test composition of two kraus errors"""

View File

@ -5,11 +5,14 @@
# 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.
from test.terra.utils import common
import unittest
"""
ReadoutError class tests
"""
from qiskit_aer.noise import ReadoutError
from qiskit_aer.noise.aernoiseerror import AerNoiseError
import unittest
from test.terra.utils import common
from qiskit_aer.noise.noiseerror import NoiseError
from qiskit_aer.noise.errors.readout_error import ReadoutError
class TestReadoutError(common.QiskitAerTestCase):
@ -18,45 +21,45 @@ class TestReadoutError(common.QiskitAerTestCase):
def test_probabilities_normalized_exception(self):
"""Test exception is raised for probabilities greater than 1."""
probs = [[0.9, 0.2], [0, 1]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
probs = [[0, 1], [0.9, 0.2]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
def test_probabilities_negative_exception(self):
"""Test exception is raised for negative probabilities."""
probs = [[1.1, -0.1], [0, 1]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
probs = [[0, 1], [1.1, -0.1]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
def test_probabilities_dimension_exception(self):
"""Test exception is raised if probabilities are not multi-qubit"""
probs = [[1, 0, 0], [0, 1, 0], [0, 1, 0]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
def test_probabilities_length_exception(self):
"""Test exception is raised if probabilities are different lengths"""
probs = [[1, 0, 0, 0], [0, 1]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
probs = [[0, 1], [1, 0, 0, 0]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
probs = [[1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 1, 0], [0, 0, 1]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
def test_probabilities_num_outcomes_exception(self):
"""Test exception is raised if not enough probability vectors"""
probs = [[0, 1]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
probs = [[1, 0], [0, 1], [0, 0]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
probs = [[1, 0, 0, 0], [0, 0, 1, 0], [0, 0, 1, 0]]
self.assertRaises(AerNoiseError, lambda: ReadoutError(probs))
self.assertRaises(NoiseError, lambda: ReadoutError(probs))
def test_1qubit(self):
"""Test reset error noise model"""

View File

@ -5,13 +5,17 @@
# 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.
import numpy as np
from test.terra.utils import common
"""
Standard error function tests
"""
import unittest
from test.terra.utils import common
import numpy as np
from qiskit.quantum_info.operators.pauli import Pauli
from qiskit_aer.noise.noise_utils import standard_gate_unitary
from qiskit_aer.noise.aernoiseerror import AerNoiseError
from qiskit_aer.noise.noiseerror import NoiseError
from qiskit_aer.noise.errors.errorutils import standard_gate_unitary
from qiskit_aer.noise.errors.standard_errors import kraus_error
from qiskit_aer.noise.errors.standard_errors import mixed_unitary_error
from qiskit_aer.noise.errors.standard_errors import coherent_unitary_error
@ -48,14 +52,14 @@ class TestNoise(common.QiskitAerTestCase):
A0 = [[1, 0], [0, np.sqrt(1 - 0.3)]]
A1 = [[0, 0], [0, np.sqrt(0.3)]]
noise_ops = [(A0, 0.5), (A1, 0.5)]
self.assertRaises(AerNoiseError, lambda: mixed_unitary_error(noise_ops))
self.assertRaises(NoiseError, lambda: mixed_unitary_error(noise_ops))
def test_mixed_unitary_error_raise_differnt_shape(self):
"""Test error is raised if input matrices different size"""
unitaries = [np.eye(4), np.eye(2)]
probs = [0.7, 0.4]
noise_ops = [(unitaries[0], probs[0]), (unitaries[1], probs[1])]
self.assertRaises(AerNoiseError, lambda: mixed_unitary_error(noise_ops))
self.assertRaises(NoiseError, lambda: mixed_unitary_error(noise_ops))
def test_mixed_unitary_error(self):
"""Test construction of mixed unitary error"""
@ -79,7 +83,7 @@ class TestNoise(common.QiskitAerTestCase):
def test_pauli_error_raise_invalid(self):
"""Test exception for invalid Pauli string"""
self.assertRaises(AerNoiseError, lambda: pauli_error([('S', 1)]))
self.assertRaises(NoiseError, lambda: pauli_error([('S', 1)]))
def test_pauli_error_1q_unitary_from_string(self):
"""Test single-qubit pauli error as unitary qobj from string label"""
@ -412,28 +416,28 @@ class TestNoise(common.QiskitAerTestCase):
def test_amplitude_damping_error_raises_invalid_amp_param(self):
"""Test phase and amplitude damping error raises for invalid amp_param"""
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(-0.5, 0, 0))
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(1.1, 0, 0))
def test_amplitude_damping_error_raises_invalid_phase_param(self):
"""Test phase and amplitude damping error raises for invalid amp_param"""
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(0, -0.5, 0))
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(0, 1.1, 0))
def test_amplitude_damping_error_raises_invalid_excited_state_pop(self):
"""Test phase and amplitude damping error raises for invalid pop"""
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(0, 0, -0.5))
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(0, 0, 1.1))
def test_amplitude_damping_error_raises_invalid_combined_params(self):
"""Test phase and amplitude damping error raises for invalid pop"""
self.assertRaises(AerNoiseError,
self.assertRaises(NoiseError,
lambda: phase_amplitude_damping_error(0.5, 0.6, 0))
def test_phase_amplitude_damping_error_noncanonical(self):
@ -571,21 +575,21 @@ class TestNoise(common.QiskitAerTestCase):
def test_thermal_relaxation_error_raises_invalid_t2(self):
"""Test raises error for invalid t2 parameters"""
# T2 == 0
self.assertRaises(AerNoiseError, lambda: thermal_relaxation_error(1, 0, 0))
self.assertRaises(NoiseError, lambda: thermal_relaxation_error(1, 0, 0))
# T2 < 0
self.assertRaises(AerNoiseError, lambda: thermal_relaxation_error(1, -1, 0))
self.assertRaises(NoiseError, lambda: thermal_relaxation_error(1, -1, 0))
def test_thermal_relaxation_error_raises_invalid_t1(self):
"""Test raises error for invalid t1 parameters"""
# T1 == 0
self.assertRaises(AerNoiseError, lambda: thermal_relaxation_error(0, 0, 0))
self.assertRaises(NoiseError, lambda: thermal_relaxation_error(0, 0, 0))
# T1 < 0
self.assertRaises(AerNoiseError, lambda: thermal_relaxation_error(-0.1, 0.1, 0))
self.assertRaises(NoiseError, lambda: thermal_relaxation_error(-0.1, 0.1, 0))
def test_thermal_relaxation_error_raises_invalid_t1_t2(self):
"""Test raises error for invalid t2 > 2 * t1 parameters"""
# T2 > 2 * T1
self.assertRaises(AerNoiseError, lambda: thermal_relaxation_error(1, 2.1, 0))
self.assertRaises(NoiseError, lambda: thermal_relaxation_error(1, 2.1, 0))
def test_thermal_relaxation_error_t1_t2_inf_ideal(self):
"""Test t1 = t2 = inf returns identity channel"""

View File

@ -9,6 +9,7 @@
StatevectorSimulator Integration Tests
"""
import unittest
from test.terra.utils import common
from test.terra.utils import ref_measure
from test.terra.utils import ref_reset
@ -17,13 +18,10 @@ from test.terra.utils import ref_1q_clifford
from test.terra.utils import ref_2q_clifford
from test.terra.utils import ref_non_clifford
from test.terra.utils import ref_unitary_gate
import unittest
from qiskit import execute
from qiskit_aer.backends import StatevectorSimulator
# TODO: Enable minimal basis (U,X) tests once bugs in terra are fixed
# TODO: Enable conditional tests once terra supports bfunc conditionals
class TestStatevectorSimulator(common.QiskitAerTestCase):
"""StatevectorSimulator tests."""

View File

@ -9,17 +9,16 @@
UnitarySimulator Integration Tests
"""
import unittest
from test.terra.utils import common
from test.terra.utils import ref_1q_clifford
from test.terra.utils import ref_2q_clifford
from test.terra.utils import ref_non_clifford
from test.terra.utils import ref_unitary_gate
import unittest
from qiskit import execute
from qiskit_aer.backends import UnitarySimulator
# TODO: Enable minimal basis (U,X) tests once bugs in terra are fixed
class TestUnitarySimulator(common.QiskitAerTestCase):
"""UnitarySimulator tests."""

View File

@ -17,9 +17,9 @@ from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit
# direclty by qobj instructions until terra compiler supports them
from qiskit import compile
from qiskit_aer.backends import QasmSimulator
from qiskit_aer.utils.qobj_utils import qobj_insert_item
from qiskit_aer.utils.qobj_utils import qobj_measure_item
from qiskit_aer.utils.qobj_utils import qobj_iden_item
from qiskit_aer.utils.qobj_utils import insert_instr
from qiskit_aer.utils.qobj_utils import measure_instr
from qiskit_aer.utils.qobj_utils import iden_instr
# ==========================================================================
@ -182,9 +182,9 @@ def measure_circuits_qobj_deterministic(allow_sampling=True):
circuit.x(qr[1])
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_measure_item([0, 1], [0, 1]), -1)
insert_instr(qobj, 0, measure_instr([0, 1], [0, 1]), -1)
if not allow_sampling:
qobj_insert_item(qobj, 0, qobj_iden_item(0), -1)
insert_instr(qobj, 0, iden_instr(0), -1)
final_qobj.experiments.append(qobj.experiments[0])
# 3-qubit measure |101>
@ -195,9 +195,9 @@ def measure_circuits_qobj_deterministic(allow_sampling=True):
circuit.x(qr[2])
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_measure_item([0, 1, 2], [0, 1, 2]), -1)
insert_instr(qobj, 0, measure_instr([0, 1, 2], [0, 1, 2]), -1)
if not allow_sampling:
qobj_insert_item(qobj, 0, qobj_iden_item(0), -1)
insert_instr(qobj, 0, iden_instr(0), -1)
final_qobj.experiments.append(qobj.experiments[0])
# 4-qubit measure |1010>
@ -208,9 +208,9 @@ def measure_circuits_qobj_deterministic(allow_sampling=True):
circuit.x(qr[3])
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_measure_item([0, 1, 2, 3], [0, 1, 2, 3]), -1)
insert_instr(qobj, 0, measure_instr([0, 1, 2, 3], [0, 1, 2, 3]), -1)
if not allow_sampling:
qobj_insert_item(qobj, 0, qobj_iden_item(0), -1)
insert_instr(qobj, 0, iden_instr(0), -1)
final_qobj.experiments.append(qobj.experiments[0])
return final_qobj
@ -264,9 +264,9 @@ def measure_circuits_qobj_nondeterministic(allow_sampling=True):
circuit.h(qr[1])
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_measure_item([0, 1], [0, 1]), -1)
insert_instr(qobj, 0, measure_instr([0, 1], [0, 1]), -1)
if not allow_sampling:
qobj_insert_item(qobj, 0, qobj_iden_item(0), -1)
insert_instr(qobj, 0, iden_instr(0), -1)
final_qobj.experiments.append(qobj.experiments[0])
# 3-qubit measure |++0>
@ -277,9 +277,9 @@ def measure_circuits_qobj_nondeterministic(allow_sampling=True):
circuit.h(qr[1])
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_measure_item([0, 1, 2], [0, 1, 2]), -1)
insert_instr(qobj, 0, measure_instr([0, 1, 2], [0, 1, 2]), -1)
if not allow_sampling:
qobj_insert_item(qobj, 0, qobj_iden_item(0), -1)
insert_instr(qobj, 0, iden_instr(0), -1)
final_qobj.experiments.append(qobj.experiments[0])
return final_qobj

View File

@ -12,11 +12,10 @@ Test circuits and reference outputs for measure instruction.
import numpy as np
from qiskit import QuantumRegister, ClassicalRegister, QuantumCircuit, compile
from qiskit_aer.backends import QasmSimulator
from qiskit_aer.utils.qobj_utils import qobj_unitary_item
from qiskit_aer.utils.qobj_utils import qobj_insert_item
from qiskit_aer.utils.qobj_utils import qobj_measure_item
from qiskit_aer.utils.qobj_utils import unitary_instr
from qiskit_aer.utils.qobj_utils import append_instr
from qiskit_aer.utils.qobj_utils import measure_instr
# ==========================================================================
@ -51,64 +50,64 @@ def unitary_gate_circuits_real_deterministic(final_measure=True):
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [0, 1]), -1)
append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX10, |00> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [1, 0]), -1)
append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX01.(X^I), |10> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(x_mat, [1]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [0, 1]), -1)
append_instr(qobj, 0, unitary_instr(x_mat, [1]))
append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX10.(I^X), |01> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(x_mat, [0]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [1, 0]), -1)
append_instr(qobj, 0, unitary_instr(x_mat, [0]))
append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX01.(I^X), |11> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(x_mat, [0]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [0, 1]), -1)
append_instr(qobj, 0, unitary_instr(x_mat, [0]))
append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX10.(X^I), |11> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(x_mat, [1]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [1, 0]), -1)
append_instr(qobj, 0, unitary_instr(x_mat, [1]))
append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
return final_qobj
@ -217,65 +216,64 @@ def unitary_gate_circuits_complex_deterministic(final_measure=True):
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [0, 1]), -1)
append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX10, |00> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [1, 0]), -1)
append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX01.(Y^I), |10> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(y_mat, [1]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [0, 1]), -1)
append_instr(qobj, 0, unitary_instr(y_mat, [1]))
append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX10.(I^Y), |01> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(y_mat, [0]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [1, 0]), -1)
append_instr(qobj, 0, unitary_instr(y_mat, [0]))
append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX01.(I^Y), |11> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(y_mat, [0]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [0, 1]), -1)
append_instr(qobj, 0, unitary_instr(y_mat, [0]))
append_instr(qobj, 0, unitary_instr(cx_mat, [0, 1]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
# CX10.(Y^I), |11> state
circuit = QuantumCircuit(*regs)
circuit.barrier(qr)
qobj = compile(circuit, QasmSimulator(), shots=1)
qobj_insert_item(qobj, 0, qobj_unitary_item(y_mat, [1]), -1)
qobj_insert_item(qobj, 0, qobj_unitary_item(cx_mat, [1, 0]), -1)
append_instr(qobj, 0, unitary_instr(y_mat, [1]))
append_instr(qobj, 0, unitary_instr(cx_mat, [1, 0]))
if final_measure:
qobj_insert_item(qobj, 0, qobj_measure_item([0], [0]), -1)
qobj_insert_item(qobj, 0, qobj_measure_item([1], [1]), -1)
append_instr(qobj, 0, measure_instr([0], [0]))
append_instr(qobj, 0, measure_instr([1], [1]))
final_qobj.experiments.append(qobj.experiments[0])
return final_qobj