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 uuid
import time
import datetime
import logging
from numpy import inf
from qiskit.result import Result
from qiskit.providers.models import BackendConfiguration, PulseDefaults
from .aerbackend import AerBackend
from ..aerjob import AerJob
from ..version import __version__
from ..pulse.qobj.digest import digest_pulse_obj
from ..pulse.solver.opsolve import opsolve

logger = logging.getLogger(__name__)


[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. **Example** To use the simulator, first :func:`~qiskit.assemble` a :class:`PulseQobj` object from a list of pulse :class:`~qiskit.Schedule` objects, using ``backend=PulseSimulator()``. Call the simulator with the :class:`PulseQobj` and a :class:`~qiskit.providers.aer.pulse.PulseSystemModel` object representing the physical system. .. 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) **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** :meth:`PulseSimulator.run` takes an additional ``dict`` argument ``backend_options`` for customization. Accepted keys: * ``'ode_options'``: A ``dict`` for ``zvode`` solver options. Accepted keys are ``'atol'``, ``'rtol'``, ``'nsteps'``, ``'max_step'``, ``'num_cpus'``, ``'norm_tol'``, and ``'norm_steps'``. """ 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': [0, 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': [] } def __init__(self, configuration=None, provider=None): # purpose of defaults is to pass assemble checks self._defaults = PulseDefaults(qubit_freq_est=[inf], meas_freq_est=[inf], buffer=0, cmd_def=[], pulse_library=[]) super().__init__(self, BackendConfiguration.from_dict(self.DEFAULT_CONFIGURATION), provider=provider)
[docs] def run(self, qobj, system_model, backend_options=None, validate=False): """Run a qobj on system_model. Args: qobj (PulseQobj): Qobj for pulse Schedules to run system_model (PulseSystemModel): Physical model to run simulation on backend_options (dict): Other options validate (bool): Flag for validation checks Returns: Result: results of simulation """ # Submit job job_id = str(uuid.uuid4()) aer_job = AerJob(self, job_id, self._run_job, qobj, system_model, backend_options, validate) aer_job.submit() return aer_job
def _run_job(self, job_id, qobj, system_model, backend_options, validate): """Run a qobj job""" start = time.time() if validate: self._validate(qobj, backend_options, noise_model=None) # Send to solver openpulse_system = digest_pulse_obj(qobj, system_model, backend_options) results = opsolve(openpulse_system) end = time.time() return self._format_results(job_id, results, end - start, qobj.qobj_id) def _format_results(self, job_id, results, time_taken, qobj_id): """Construct Result object from simulator output.""" # Add result metadata output = {} output['qobj_id'] = qobj_id output['results'] = results output['success'] = True output["job_id"] = job_id output["date"] = datetime.datetime.now().isoformat() output["backend_name"] = self.name() output["backend_version"] = self.configuration().backend_version output["time_taken"] = time_taken return Result.from_dict(output)
[docs] def defaults(self): """Return defaults. Returns: PulseDefaults: object for passing assemble. """ return self._defaults