mirror of https://github.com/Qiskit/qiskit-aer.git
Merge pull request #149 from cjwood/feature/backend-options
Cleaning up names and doctrings
This commit is contained in:
commit
4b0cddda0b
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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):
|
|
@ -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
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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. "
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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}
|
||||
|
|
@ -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):
|
|
@ -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)
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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):
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
|
|
|
@ -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:
|
||||
//----------------------------------------------------------------
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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:
|
||||
//-----------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
//-----------------------------------------------------------------------
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
//-----------------------------------------------------------------------
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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:
|
||||
//-----------------------------------------------------------------------
|
||||
|
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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"""
|
|
@ -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"""
|
|
@ -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"""
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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."""
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue