English
Languages
English
Japanese
German
Korean
Portuguese, Brazilian
French
Shortcuts

Source code for qiskit.providers.aer.backends.pulse_simulator

# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019, 2020.
#
# This code is licensed under the Apache License, Version 2.0. You may
# obtain a copy of this license in the LICENSE.txt file in the root directory
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
#
# Any modifications or derivative works of this code must retain this
# copyright notice, and modified files need to carry a notice indicating
# that they have been altered from the originals.
# pylint: disable=arguments-differ, missing-return-type-doc
"""
Qiskit Aer pulse simulator backend.
"""

import copy
import logging
from warnings import warn
from numpy import inf

from qiskit.providers.models import BackendConfiguration, PulseDefaults

from ..version import __version__
from ..aererror import AerError
from ..pulse.controllers.pulse_controller import pulse_controller
from ..pulse.system_models.pulse_system_model import PulseSystemModel
from .aerbackend import AerBackend

logger = logging.getLogger(__name__)

DEFAULT_CONFIGURATION = {
    'backend_name': 'pulse_simulator',
    'backend_version': __version__,
    'n_qubits': 20,
    'coupling_map': None,
    'url': 'https://github.com/Qiskit/qiskit-aer',
    'simulator': True,
    'meas_levels': [1, 2],
    'local': True,
    'conditional': True,
    'open_pulse': True,
    'memory': False,
    'max_shots': int(1e6),
    'description': 'A Pulse-based Hamiltonian simulator for Pulse Qobj files',
    'gates': [],
    'basis_gates': []
}


[docs]class PulseSimulator(AerBackend): r"""Pulse schedule simulator backend. The ``PulseSimulator`` simulates continuous time Hamiltonian dynamics of a quantum system, with controls specified by pulse :class:`~qiskit.Schedule` objects, and the model of the physical system specified by :class:`~qiskit.providers.aer.pulse.PulseSystemModel` objects. Results are returned in the same format as when jobs are submitted to actual devices. **Examples** The minimal information a ``PulseSimulator`` needs to simulate is a :class:`~qiskit.providers.aer.pulse.PulseSystemModel`, which can be supplied either by setting the backend option before calling ``run``, e.g.: .. code-block:: python backend_sim = qiskit.providers.aer.PulseSimulator() # Set the pulse system model for the simulator backend_sim.set_options(system_model=system_model) # Assemble schedules using PulseSimulator as the backend pulse_qobj = assemble(schedules, backend=backend_sim) # Run simulation results = backend_sim.run(pulse_qobj) or by supplying the system model at runtime, e.g.: .. code-block:: python backend_sim = qiskit.providers.aer.PulseSimulator() # Assemble schedules using PulseSimulator as the backend pulse_qobj = assemble(schedules, backend=backend_sim) # Run simulation on a PulseSystemModel object results = backend_sim.run(pulse_qobj, system_model=system_model) Alternatively, an instance of the ``PulseSimulator`` may be further configured to contain more information present in a real backend. The simplest way to do this is to instantiate the ``PulseSimulator`` from a real backend: .. code-block:: python armonk_sim = qiskit.providers.aer.PulseSimulator.from_backend(FakeArmonk()) pulse_qobj = assemble(schedules, backend=armonk_sim) armonk_sim.run(pulse_qobj) In the above example, the ``PulseSimulator`` copies all configuration and default data from ``FakeArmonk()``, and as such has the same affect as ``FakeArmonk()`` when passed as an argument to ``assemble``. Furthermore it constructs a :class:`~qiskit.providers.aer.pulse.PulseSystemModel` from the model details in the supplied backend, which is then used in simulation. **Supported PulseQobj parameters** * ``qubit_lo_freq``: Local oscillator frequencies for each :class:`DriveChannel`. Defaults to either the value given in the :class:`~qiskit.providers.aer.pulse.PulseSystemModel`, or is calculated directly from the Hamiltonian. * ``meas_level``: Type of desired measurement output, in ``[1, 2]``. ``1`` gives complex numbers (IQ values), and ``2`` gives discriminated states ``|0>`` and ``|1>``. Defaults to ``2``. * ``meas_return``: Measurement type, ``'single'`` or ``'avg'``. Defaults to ``'avg'``. * ``shots``: Number of shots per experiment. Defaults to ``1024``. **Simulation details** The simulator uses the ``zvode`` differential equation solver method through ``scipy``. Simulation is performed in the rotating frame of the diagonal of the drift Hamiltonian contained in the :class:`~qiskit.providers.aer.pulse.PulseSystemModel`. Measurements are performed in the `dressed basis` of the drift Hamiltonian. **Other options** Additional valid keyword arguments for ``run()``: * ``'solver_options'``: A ``dict`` for solver options. Accepted keys are ``'atol'``, ``'rtol'``, ``'nsteps'``, ``'max_step'``, ``'num_cpus'``, ``'norm_tol'``, and ``'norm_steps'``. """
[docs] def __init__(self, configuration=None, properties=None, defaults=None, provider=None, **backend_options): if configuration is None: configuration = BackendConfiguration.from_dict( DEFAULT_CONFIGURATION) else: configuration = copy.copy(configuration) configuration.meas_levels = self._meas_levels(configuration.meas_levels) if defaults is None: defaults = PulseDefaults(qubit_freq_est=[inf], meas_freq_est=[inf], buffer=0, cmd_def=[], pulse_library=[]) super().__init__(configuration, properties=properties, defaults=defaults, provider=provider, backend_options=backend_options) # Set up default system model subsystem_list = backend_options.get('subsystem_list', None) if backend_options.get('system_model') is None: if hasattr(configuration, 'hamiltonian'): system_model = PulseSystemModel.from_config( configuration, subsystem_list) self._set_system_model(system_model)
# pylint: disable=arguments-differ, missing-param-doc
[docs] def run(self, qobj, *args, backend_options=None, # DEPRECATED validate=True, **run_options): """Run a qobj on the backend. Args: qobj (QasmQobj): The Qobj to be executed. backend_options (dict or None): DEPRECATED dictionary of backend options for the execution (default: None). validate (bool): validate the Qobj before running (default: True). run_options (kwargs): additional run time backend options. Returns: AerJob: The simulation job. Additional Information: * kwarg options specified in ``run_options`` will override options of the same kwarg specified in the simulator options, the ``backend_options`` and the ``Qobj.config``. * The entries in the ``backend_options`` will be combined with the ``Qobj.config`` dictionary with the values of entries in ``backend_options`` taking precedence. This kwarg is deprecated and direct kwarg's should be used for options to pass them to ``run_options``. """ if args: if isinstance(args[0], PulseSystemModel): warn( 'Passing `system_model` as a positional argument to' ' `PulseSimulator.run` has been deprecated as of' ' qiskit-aer 0.7.0 and will be removed no earlier than 3' ' months from that release date. Pass `system_model` as a kwarg' ' `system_model=model` instead.', DeprecationWarning, stacklevel=3) run_options['system_model'] = args[0] if len(args) > 1: backend_options = args[1] if len(args) > 2: validate = args[3] elif isinstance(args[0], bool): validate = args[0] if len(args) > 1: backend_options = args[1] return super().run(qobj, backend_options=backend_options, validate=validate, **run_options)
@property def _system_model(self): return self._options.get('system_model')
[docs] @classmethod def from_backend(cls, backend, **options): """Initialize simulator from backend.""" configuration = copy.copy(backend.configuration()) defaults = copy.copy(backend.defaults()) properties = copy.copy(backend.properties()) backend_name = 'pulse_simulator({})'.format(configuration.backend_name) description = 'A Pulse-based simulator configured from the backend: ' description += configuration.backend_name sim = cls(configuration=configuration, properties=properties, defaults=defaults, backend_name=backend_name, description=description, **options) return sim
def _execute(self, qobj): """Execute a qobj on the backend. Args: qobj (PulseQobj): simulator input. Returns: dict: return a dictionary of results. """ qobj.config.qubit_freq_est = self.defaults().qubit_freq_est return pulse_controller(qobj) def _set_option(self, key, value): """Set pulse simulation options and update backend.""" if key == 'meas_levels': self._set_configuration_option(key, self._meas_levels(value)) return # Handle cases that require updating two places if key in ['dt', 'u_channel_lo']: self._set_configuration_option(key, value) if self._system_model is not None: setattr(self._system_model, key, value) return if key == 'hamiltonian': # if option is hamiltonian, set in configuration and reconstruct pulse system model subsystem_list = self._options.get('subsystem_list', None) system_model = PulseSystemModel.from_config(self.configuration(), subsystem_list) super()._set_option('system_model', system_model) self._set_configuration_option(key, value) return # if system model is specified directly if key == 'system_model': if hasattr(self.configuration(), 'hamiltonian'): warn('Specifying both a configuration with a Hamiltonian and a ' 'system model may result in inconsistencies.') # Set config dt and u_channel_lo to system model values self._set_system_model(value) return # Set all other options from AerBackend super()._set_option(key, value) def _set_system_model(self, system_model): """Set system model option""" self._set_configuration_option( 'dt', getattr(system_model, 'dt', [])) self._set_configuration_option( 'u_channel_lo', getattr(system_model, 'u_channel_lo', [])) super()._set_option('system_model', system_model) def _validate(self, qobj): """Validation of qobj. Ensures that exactly one Acquire instruction is present in each schedule. Checks SystemModel is in qobj config """ if getattr(qobj.config, 'system_model', None) is None: raise AerError("PulseSimulator requires a system model to run.") for exp in qobj.experiments: num_acquires = 0 for instruction in exp.instructions: if instruction.name == 'acquire': num_acquires += 1 if num_acquires > 1: raise AerError("PulseSimulator does not support multiple Acquire " "instructions in a single schedule.") if num_acquires == 0: raise AerError("PulseSimulator requires at least one Acquire " "instruction per schedule.") @staticmethod def _meas_levels(meas_levels): """Function for setting meas_levels in a pulse simulator configuration.""" if 0 in meas_levels: warn('Measurement level 0 not supported in pulse simulator.') tmp = copy.copy(meas_levels) tmp.remove(0) return tmp return meas_levels

© Copyright 2020, Qiskit Development Team. Last updated on 2021/05/25.

Built with Sphinx using a theme provided by Read the Docs.