Skip to content

Commit

Permalink
merge main
Browse files Browse the repository at this point in the history
  • Loading branch information
BrunoLiegiBastonLiegi committed Jan 7, 2025
2 parents ffa25f7 + 9522c5b commit 13ac652
Show file tree
Hide file tree
Showing 15 changed files with 707 additions and 3,160 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -157,5 +157,7 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
*.idea
*.iml
.idea/
.devenv
8 changes: 4 additions & 4 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ ci:
autofix_prs: true
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.6.0
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: debug-statements
- repo: https://github.com/psf/black
rev: 24.8.0
rev: 24.10.0
hooks:
- id: black
- repo: https://github.com/pycqa/isort
Expand All @@ -18,11 +18,11 @@ repos:
- id: isort
args: ["--profile", "black"]
- repo: https://github.com/asottile/pyupgrade
rev: v3.17.0
rev: v3.19.1
hooks:
- id: pyupgrade
- repo: https://github.com/hadialqattan/pycln
rev: v2.4.0
rev: v2.5.0
hooks:
- id: pycln
args: [--config=pyproject.toml]
Binary file added doc/source/IQM_Garnet_topology.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion doc/source/backends.rst
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,24 @@ This backend supports IBM as provider, namely the qibo circuits are loaded as qi
The :meth:`qibo_cloud_backends.qiskit_client.QiskitClientBackend.execute_circuit` does not take care of any transpilation and expects the passed circuit to be transpiled already.

.. note::
Circuits with no measurements are not supported yet. Remeber to add measurements to your circuit!
Circuits with no measurements are not supported yet. Remember to add measurements to your circuit!

.. autoclass:: qibo_cloud_backends.qiskit_client.QiskitClientBackend
:members:
:member-order: bysource


Braket Backend
^^^^^^^^^^^^^^

This backend provides support for AWS Braket devices, ranging from the LocalSimulator to the devices available on Amazon Braket. Here, Qibo circuits are translated into Braket circuits and sent to the Braket device. There is an additional option to submit a Qibo circuit written in the device's native gates and targeting specific qubits, fully avoiding any transpilation. This can be done by changing the default setting from `verbatim_circuit=False` to `verbatim_circuit=True`.

.. note::
If `verbatim_circuit=True`, the Qibo circuit only undergoes translation to a Braket circuit before execution on :meth:`qibo_cloud_backends.braket_client.BraketClientBackend.execute_circuit`. No transpilation will take place on the Braket device. A warning will be raised by the device if the qubits are out of range or if it detects non-native gates.

.. note::
Circuits with no measurements are not supported yet. Remember to add measurements to your circuit!

.. autoclass:: qibo_cloud_backends.braket_client.BraketClientBackend
:members:
:member-order: bysource
8 changes: 8 additions & 0 deletions doc/source/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ or, in order to use the `ibm_kyiv` platform on the IBM `ibm-q` server:
result = circuit()
print(result.frequencies())
To use Amazon Braket devices, refer to :ref:`tutorials` for a tutorial on using the Braket client.

API Reference
=============

Expand All @@ -70,6 +72,12 @@ API Reference

backends

.. toctree::
:maxdepth: 2
:caption: Tutorials:

tutorials

.. toctree::
:maxdepth: 1
:caption: Documentation links
Expand Down
280 changes: 280 additions & 0 deletions doc/source/tutorials.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
.. _tutorials:

Using Braket Client
-------------------


.. _register_account:

Registering for an AWS Account
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

The usage of the Amazon Braket LocalSimulator does not require an account. However, to use Amazon Braket devices such as the statevector simulator and hardware, the user needs to register for an account here: https://signin.aws.amazon.com/signup?request_type=register.

The user also needs to ensure the prerequisites have been configured. More information can be found here: https://github.com/amazon-braket/amazon-braket-sdk-python#prerequisites.


.. _execute_a_circuit:

Submit a circuit
^^^^^^^^^^^^^^^^

In this example, we will demonstrate how to submit a Qibo circuit onto an Amazon Braket device. We will use IQM Garnet as an example. Note that by default `verbatim_circuit=False`, therefore the transpilation of the input circuit and assignment of the best qubits to use will be left to the device.

To use BraketClientBackend, we import `BraketClientBackend` from `qibo_cloud_backends.braket_client`:

.. code-block:: python
from qibo_cloud_backend.braket_client import BraketClientBackend
Then, construct a Qibo circuit.

.. code-block:: python
from qibo import gates, Circuit as QiboCircuit
c = QiboCircuit(2)
c.add(gates.H(0))
c.add(gates.CNOT(0, 1))
c.add(gates.M(0))
c.add(gates.M(1))
print(c.draw())
We should get this circuit:

.. code-block:: python
q0: -H-o-M-
q1: ---x-M-
Now, we initialize a Amazon Braket device (e.g. IQM Garnet) and execute circuit `c` on the backend `AWS`.

.. code-block:: python
device = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet"
AWS = BraketClientBackend(device = device, verbatim_circuit=False)
counts = AWS.execute_circuit(c, nshots=1000).frequencies()
print(counts)
Alternatively, one can also use the LocalSimulator to execute circuit `c`. This can be done by leaving `device` empty as it defaults to the LocalSimulator.

.. code-block:: python
AWS = BraketClientBackend(verbatim_circuit=False)
counts = AWS.execute_circuit(c, nshots=1000).frequencies()
print(counts)
To monitor the status of a circuit that is executed, especially on an Amazon Braket device, one can set `verbosity=True`. By default, `verbosity=False`.

.. code-block:: python
device = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet"
AWS = BraketClientBackend(device = device, verbatim_circuit=False, verbosity=True)
counts = AWS.execute_circuit(c, nshots=1000).frequencies()
print(counts)
One can also use the density matrix local simulator by specifying `device = "local_simulator:braket_dm"`.


.. _execute_in_verbatim_mode:

Submit a circuit in verbatim mode
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In verbatim mode, the circuit is executed on the device without any transpilation. The user has to ensure that the circuit is specifically written in the device's native gates and gates respect the topology of the device.
Therefore, before submitting a Qibo circuit in verbatim mode, it is recommended to extract the Amazon Braket device's information. We will demonstrate this below.

.. _Amazon_Braket_parameters:

Extracting Amazon Braket device parameters
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The Amazon Braket devices can be found here: https://aws.amazon.com/braket/quantum-computers/. Using the `IQM Garnet device <https://aws.amazon.com/braket/quantum-computers/iqm/>`_ as an example, we demonstrate how to extract useful device information such as the qubit topology and native gates. The qubit connectivity on the IQM Garnet device can be visualised using `NetworkX <https://networkx.org/>`_.

.. code-block:: python
import networkx as nx
device = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet"
connectivity_graph = AwsDevice(device).properties.paradigm.connectivity.connectivityGraph
native_gates = AwsDevice(device).properties.paradigm.nativeGateSet
print(native_gates)
G = nx.Graph()
for node, neighbors in connectivity_graph.items():
for neighbor in neighbors:
G.add_edge(node, neighbor)
nx.draw(G, pos=nx.spring_layout(G), with_labels=True, node_color='lightblue', node_size=500, font_size=10, font_weight='bold', edge_color='gray')
Submit the circuit
~~~~~~~~~~~~~~~~~~

Let us run a circuit with `verbatim_circuit=True` on an Amazon Braket device, using IQM Garnet as an example. When `verbatim_circuit=True`, the circuit is submitted as is onto the Amazon Braket device. The device expects to receive a circuit composed of its native gates only and with entangling gates that respect its connectivity (entangling gates can be executed only on qubit pairs that are physically connected on the chip). For IQM Garnet, for instance, the native gates are `CZ` and `PRX` and the connectivity is a square lattice of 20 qubits.

.. code-block:: python
from qibo import gates, Circuit as QiboCircuit
import numpy as np
c = QiboCircuit(5)
c.add(gates.PRX(1, 0.5*np.pi, 1.5*np.pi))
c.add(gates.PRX(4, 0.142857142857143*np.pi, 0))
c.add(gates.CZ(4, 1))
c.add(gates.PRX(1, 0.5*np.pi, 0.5*np.pi))
c.add(gates.M(1))
c.add(gates.M(4))
print(c.draw())
We should get this circuit:

.. code-block:: python
q0: -------------
q1: -prx-Z-prx-M-
q2: -----|-------
q3: -----|-------
q4: -prx-o-M-----
Since IQM Garnet has qubits indexed from 1 to 20, we will intentionally leave qubit `q0` empty without any gates. An error will be raised if there are gates on any qubits not in the range from 1 to 20.

Now, we initialize the `BraketClientBackend` with the `Garnet` device and execute the circuit `c` with it.

.. code-block:: python
device = "arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet"
AWS = BraketClientBackend(device = device, verbatim_circuit=True)
counts = AWS.execute_circuit(c, nshots=1000).frequencies()
print(counts)
.. _ZNE_example:

Example: Using Zero Noise Extrapolation
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

In this example, we illustrate the use of Zero Noise Extrapolation (ZNE) to improve the results of a Quantum Approximate Optimization Algorithm (QAOA) circuit. The circuit solves a trivial MaxCut problem with a single QAOA layer. We just need to set up Qibo's `ZNE <https://qibo.science/qibo/stable/api-reference/qibo.html#zero-noise-extrapolation-zne>`_ routine with our initialized `BraketClientBackend`.

Here, we make several assumptions:

1. The user is able to transpile any Qibo circuit to IQM Garnet's native gates and to fit IQM Garnet's qubit topology.

2. The optimal angles for the single QAOA layer are known.

With these assumptions met, we then transpile the QAOA circuit that looks like this

.. code-block:: python
q0: -H-o----o-o----o-o----o---------------RX-M-
q1: -H-X-RZ-X-|----|-|----|-o----o--------RX-M-
q2: -H--------X-RZ-X-|----|-X-RZ-X-o----o-RX-M-
q3: -H---------------X-RZ-X--------X-RZ-X-RX-M-
to the following circuit `c` written in IQM Garnet's native gates, targeting specific qubits that respect the topology shown in :ref:`IQM_Garnet_topology`. The optimal parameters for the `RZ` and `RX` gates are not shown in this circuit above.

The topology was obtained using the code in the section :ref:`Amazon_Braket_parameters`. The parameters for the `PRX` gates are optimal. We select `verbatim_circuit=True` as we do not want the device to transpile the circuit.

.. _IQM_Garnet_topology:

.. figure:: IQM_Garnet_topology.png
:alt: IQM Garnet topology.
:align: center
:width: 600px

Figure 1: IQM Garnet topology.

Writing the transpiled circuit `c` in full, we have:

.. code-block:: python
c = QiboCircuit(10):
c.add(gates.PRX(3, -np.pi, np.pi/2))
c.add(gates.PRX(3, np.pi, -np.pi/2))
c.add(gates.PRX(4, np.pi/2, np.pi/2))
c.add(gates.PRX(4, np.pi, 0))
c.add(gates.CZ(3, 4))
c.add(gates.PRX(3, -1.081592653589793, 0))
c.add(gates.PRX(3, np.pi, -np.pi))
c.add(gates.CZ(3, 4))
c.add(gates.PRX(3, np.pi/2, np.pi/2))
c.add(gates.PRX(3, np.pi, 0))
c.add(gates.PRX(5, -np.pi, np.pi/2))
c.add(gates.PRX(5, np.pi, -np.pi/2))
c.add(gates.PRX(9, -np.pi, np.pi/2))
c.add(gates.PRX(9, np.pi, -np.pi/2))
c.add(gates.CZ(4, 9))
c.add(gates.PRX(9, -1.081592653589793, 0))
c.add(gates.PRX(9, np.pi, -np.pi))
c.add(gates.CZ(4, 9))
c.add(gates.CZ(4, 5))
c.add(gates.PRX(5, -1.081592653589793, 0))
c.add(gates.PRX(5, np.pi, -np.pi))
c.add(gates.CZ(4, 5))
c.add(gates.PRX(4, 2.850796326794897, 0))
c.add(gates.PRX(5, -np.pi, np.pi/2))
c.add(gates.PRX(5, np.pi, -np.pi/2))
c.add(gates.PRX(9, -np.pi/2, -np.pi))
c.add(gates.PRX(9, np.pi, -np.pi/4))
c.add(gates.CZ(4, 9))
c.add(gates.PRX(4, np.pi/2, 0))
c.add(gates.PRX(9, np.pi/2, 0))
c.add(gates.CZ(4, 9))
c.add(gates.PRX(4, np.pi/2, 0))
c.add(gates.PRX(9, np.pi/2, 0))
c.add(gates.CZ(4, 9))
c.add(gates.PRX(4, np.pi/2, np.pi/2))
c.add(gates.PRX(4, np.pi, 0))
c.add(gates.CZ(3, 4))
c.add(gates.PRX(4, -1.081592653589793, 0))
c.add(gates.PRX(4, np.pi, -np.pi))
c.add(gates.CZ(3, 4))
c.add(gates.PRX(3, 1.28, 0))
c.add(gates.PRX(4, np.pi/2, np.pi/2))
c.add(gates.PRX(4, np.pi, 0))
c.add(gates.CZ(4, 5))
c.add(gates.PRX(4, -1.081592653589793, 0))
c.add(gates.PRX(4, np.pi, -np.pi))
c.add(gates.CZ(4, 5))
c.add(gates.PRX(4, 1.28, 0))
c.add(gates.PRX(5, -np.pi/2, -2.850796326794897))
c.add(gates.PRX(5, np.pi, -0.64)
c.add(gates.M(9, 3, 4, 5))
The next step is to define the problem Hamiltonian of the QAOA for MaxCut, `obs`, that is adapted to fit the manually transpiled circuit `c` constructed above.
.. code-block:: python
from qibo.symbols import Z
from qibo.hamiltonians import SymbolicHamiltonian
obs = 2.5 - 0.5*Z(3)*Z(9) - 0.5*Z(4)*Z(3) - 0.5*Z(4)*Z(5) - 0.5*Z(4)*Z(9) - 0.5*Z(9)*Z(5)
obs = SymbolicHamiltonian(obs, nqubits=c.nqubits, backend=NumpyBackend())
Finally, with the transpiled circuit `c` and the problem Hamiltonian `obs`, we can run ZNE using `BraketClientBackend` with verbatim mode enabled to obtain the estimated (extrapolated) result.
.. code-block:: python
from qibo.models.error_mitigation import get_noisy_circuit, ZNE
device = AwsDevice('arn:aws:braket:eu-north-1::device/qpu/iqm/Garnet')
AWS = BraketClientBackend(device = device, verbatim_circuit=True)
shots=1000
estimate = ZNE(
circuit=c,
observable=obs,
noise_levels=np.array(range(5)),
nshots=shots,
backend=AWS,
)
print(estimate)
.. note::
Running circuits on an Amazon Braket device (other than LocalSimulator) incurs cost. The pricing can be found on https://aws.amazon.com/braket/pricing/.
Loading

0 comments on commit 13ac652

Please sign in to comment.