Source code for qiskit.providers.aer.aerjob

# This code is part of Qiskit.
#
# (C) Copyright IBM 2018, 2019.
#
# 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

"""This module implements the job class used for AerBackend objects."""

from concurrent import futures
import logging
import functools

from qiskit.providers import BaseJob, JobStatus, JobError

logger = logging.getLogger(__name__)


def requires_submit(func):
    """
    Decorator to ensure that a submit has been performed before
    calling the method.

    Args:
        func (callable): test function to be decorated.

    Returns:
        callable: the decorated function.
    """
    @functools.wraps(func)
    def _wrapper(self, *args, **kwargs):
        if self._future is None:
            raise JobError("Job not submitted yet!. You have to .submit() first!")
        return func(self, *args, **kwargs)
    return _wrapper


[docs]class AerJob(BaseJob): """AerJob class. Attributes: _executor (futures.Executor): executor to handle asynchronous jobs """ _executor = futures.ThreadPoolExecutor(max_workers=1) def __init__(self, backend, job_id, fn, qobj, *args): super().__init__(backend, job_id) self._fn = fn self._qobj = qobj self._args = args self._future = None
[docs] def submit(self): """Submit the job to the backend for execution. Raises: QobjValidationError: if the JSON serialization of the Qobj passed during construction does not validate against the Qobj schema. JobError: if trying to re-submit the job. """ if self._future is not None: raise JobError("We have already submitted the job!") self._future = self._executor.submit(self._fn, self._job_id, self._qobj, *self._args)
[docs] @requires_submit def result(self, timeout=None): # pylint: disable=arguments-differ """Get job result. The behavior is the same as the underlying concurrent Future objects, https://docs.python.org/3/library/concurrent.futures.html#future-objects Args: timeout (float): number of seconds to wait for results. Returns: qiskit.Result: Result object Raises: concurrent.futures.TimeoutError: if timeout occurred. concurrent.futures.CancelledError: if job cancelled before completed. """ return self._future.result(timeout=timeout)
[docs] @requires_submit def cancel(self): return self._future.cancel()
[docs] @requires_submit def status(self): """Gets the status of the job by querying the Python's future Returns: JobStatus: The current JobStatus Raises: JobError: If the future is in unexpected state concurrent.futures.TimeoutError: if timeout occurred. """ # The order is important here if self._future.running(): _status = JobStatus.RUNNING elif self._future.cancelled(): _status = JobStatus.CANCELLED elif self._future.done(): _status = JobStatus.DONE if self._future.exception() is None else JobStatus.ERROR else: # 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
[docs] def backend(self): """Return the instance of the backend used for this job.""" return self._backend
[docs] def qobj(self): """Return the Qobj submitted for this job. Returns: Qobj: the Qobj submitted for this job. """ return self._qobj