Execution
=========

.. code-block:: python

    from mpqp.execution import *

Execution is the core of this library. Our goal is to allow you to run a circuit
on any hardware without you having to rewrite your circuit in the providers'
``sdk``. We introduce here how execution works in ``mpqp``, both in local
simulator and in remote QPUs.

Devices
-------

The abstract class
:class:`AvailableDevice<mpqp.execution.devices.AvailableDevice>` represents any
device on which one can run or submit a circuit. Extending the ``Enum`` class,
it regroups methods common to all providers' devices.

.. autoclass:: mpqp.execution.devices.AvailableDevice

Then, for each supported quantum computer/simulator provider, we create a
specific subclass enumerating all available devices. When devices are retrieved
using a given name (a string), we use it to set the value associated with each key
of the :class:`AvailableDevice<mpqp.execution.devices.AvailableDevice>`.
Specific device's info and manipulation are handled by additional methods
(sometimes static).

.. autoclass:: mpqp.execution.devices.IBMDevice

.. autoclass:: mpqp.execution.devices.ATOSDevice

.. autoclass:: mpqp.execution.devices.AWSDevice

Setting up a remote device
--------------------------

Installing MPQP gives you access to a script facilitating the setting up of
remote QPU connections. The three supported providers can be setup from this
script, called ``setup_connections``. Each of these providers have their own set
of data needed to setup the connection, summed up here:

- IBM quantum (qiskit): for this provider, you only need your account ``API
  token``, which you can find in your `account page <https://quantum.ibm.com/account>`_;
- Atos/Eviden (Qaptiva/QLM): for this provider, several connection methods
  exist. For now we only support the username/password method. You should have
  received you username and password by email;
- AWS (braket): for this provider, you will need more information: all of them can
  be found in your 
  `AWS console <https://console.aws.amazon.com/console/home?nc2=h_ct&src=header-signin>`_.
  In the console go to the ``IAM service``, in the ``Users`` tab, click on your
  username, in the ``Security credential`` tab, you'll find an ``Access keys`` 
  section. In this section, you can create a new access key for MPQP, you should
  save it because you will not be able to get back your secret latter on.
  This will give you your key and your secret, but for the configuration you also
  need a region (for example ``us-east-1``).
  In short, one would need:

  + ``AWS Access Key ID``,
  + ``AWS Secret Access Key`` and
  + ``Default region name``.

.. TODO: this is a duplicate from a section in the getting-started page, merge 
.. the two to keep only what's better.

Run a circuit
-------------

Once the circuit is defined, and eventually a measurement attached to it, one
would ultimately want to execute the circuit and retrieve the associated result.
By using the function :func:`run<mpqp.execution.runner.run>`, one can execute
this circuit, on one or several devices (local or remote). The function will
wait (blocking) until the job is completed and will return a
:class:`Result<mpqp.execution.result.Result>` or
:class:`BatchResult<mpqp.execution.result.BatchResult>` (see
:ref:`below<Results>`).

.. autofunction:: mpqp.execution.runner.run

Submit a circuit
----------------

When running jobs on a remote device, one would like to retrieve the result
asynchronously, without having to wait and block the application until the
computation is completed. In that case, one should use the function
:func:`submit<mpqp.execution.runner.submit>`, that submits the job to the remote
device, and returns the corresponding job id and
:class:`Job<mpqp.execution.job.Job>` object.

.. note::
    Unlike ``run``, we can only submit a single circuit on a single device.

.. autofunction:: mpqp.execution.runner.submit

.. automodule:: mpqp.execution.remote_handler


Jobs
----

When the user calls :func:`run<mpqp.execution.runner.run>` or
:func:`submit<mpqp.execution.runner.submit>` with a given circuit and device, an
instance of :class:`Job<mpqp.execution.job.Job>` is generated by the function
:func:`generate_job<mpqp.execution.runner.generate_job>`. This job contains all
the needed information to configure the execution, and eventually retrieve
remote results.

A :class:`Job<mpqp.execution.job.Job>` can be of three types, and this is
handled by the ``Enum`` class :class:`JobType<mpqp.execution.job.JobType>`
described below.

.. autoclass:: mpqp.execution.job.JobType

Through the whole computation process, locally or remotely, the status of a job
can change. We keep track of this status using the ``Enum`` class
:class:`JobStatus<mpqp.execution.job.JobStatus>`.

.. autoclass:: mpqp.execution.job.JobStatus

During the initialization of the running process, an instance of
:class:`Job<mpqp.execution.job.Job>` is automatically generated, and thus a user
would in principle never need to instantiate one by himself. The class is
described below, with the associated attributes and properties.

.. autoclass:: mpqp.execution.job.Job

.. _Results:

Results
-------

Once the computation ended on the remote or local device, we retrieve an object
:class:`Result<mpqp.execution.result.Result>` containing the result of the
requested measurement.

.. autoclass:: mpqp.execution.result.Result

When the job was of type ``STATE_VECTOR``, the user can retrieve a
:class:`StateVector<mpqp.execution.result.StateVector>` by calling
``result.state_vector``. The class manages the inference of number of qubits and
probabilities from the
vector of amplitudes.

.. autoclass:: mpqp.execution.result.StateVector

When the job was of type ``SAMPLE``, we want to retrieve the counts (and
eventually the probabilities) for each basis state. This is done by using the
object :class:`Sample<mpqp.execution.result.Sample>` that stores the counts and
probability to measure it, and also the switch between a binary string
representation and the index of the basis state. A list of samples is then
stored in the result.

.. autoclass:: mpqp.execution.result.Sample

When several devices were given to the :func:`run<mpqp.execution.runner.run>` or
:func:`submit<mpqp.execution.runner.submit>`, the different results are stored
in a :class:`BatchResult<mpqp.execution.result.BatchResult>`, managing for
instance the print of several results at the same time.

.. autoclass:: mpqp.execution.result.BatchResult