diff --git a/docs/contributing/add_new_backend.md b/docs/contributing/add_new_backend.md new file mode 100644 index 0000000..56d0544 --- /dev/null +++ b/docs/contributing/add_new_backend.md @@ -0,0 +1,47 @@ +# Adding a new Backend Plug-in in OpenQAOA + +Since OpenQAOA is designed with modularity and multi-backend support in mind a user can easily add a new backend plugin in OpenQAOA. +OpenQAOA distinguishes between parts of the QAOA workflow that are a backend agnositc and backend dependent. The backend agnostic parts that can be abstracted away uniformly across all devices and cloud providers form the core functionality of the package, and are therefore, placed in `openqaoa-core`. The parts that are specific to each backend device or cloud provider are placed in their respective plugins. Therefore, to run a QAOA workflow on Amazon AWS quantum computers, one needs `openqaoa-core` for the backend agnostic components and `openqaoa-braket` to communicate with the devices on AWS Braket. + +In similar spirit, one can add new backends that add a new hardware provider to the existing list of openqaoa plugins. This tutorial provides a guide on how to begin adding a new backend plugin. For the rest of this tutorial, we assume that the new backend will be called `xyz` + +## Create the new plugin folder + +- Create a new folder `/src/openqaoa-xyz` + +This folder will contain all the necessary code to support the new `XYZ` plugin. +Within this folder will be the following files containing instructions to convert the plugin into an installable package: +- LICENSE: Since OpenQAOA is licensed using MIT License, the individual plugins will follow the same license as well. +- MANIFEST.in: This file will include the requirements file to install package dependencies for `openqaoa-xyz` +- pyproject.toml: This file should contain the following instructions + ```Python + [build-system] + requires = ["setuptools>=61.0"] + build-backend = "setuptools.build_meta" + ``` +- README.md: A readme file to describe the plugin +- requirements.txt: A textfile describing all the necessary python dependencies for the plugin +- setup.py: Setup instructions to install the package as a python module +- tests/ : A tests folder containing all backend specific unit-tests for the new plugin + +All the code supporting this new plugin will go inside a `src/openqaoa-xyz/openqaoa_xyz`. The naming conventions of all files and folders are crucial for the proper functioning of the plugin. + +### `openqaoa_xyz` +The folder contains the following: +- `__init__.py`: +- `_version.py`: This file should set the same version number of the plugin as `openqaoa-core` +- backend_config.py: This file should contain instructions on how the plugin device object is paired to the QAOABackend object. + +Finally, the code implementation of the device and backend lives inside the `src/openqaoa-xyz/openqaoa_xyz/backends` folder. This folder contains three different kinds of files: + +- `gates_xyz.py`: This file provides a mapping between the gates in the OpenQAOA intermediate representation and the gates of the backend, and an implementation of the `apply_gate` methods that are used by `openqaoa-core` to construct the QAOA circuit. All these functions are implemented as methods of the `XYZGateApplicator` class. + +- `devices.py`: Implement the `DeviceXYZ` object here. The user must pay attention towards the requirements for the specific cloud provider and their methods of authentication. These must be built into the device object. Moreover, this object must inherit from the `DeviceBase` object defined in `openqaoa-core` + +- `qaoa_xyz.py`: The name of this file can be chosen at will. The file should contain the QAOA Backend implementation for the `XYZ` hardware provider. It must contain the basic methods expected from a QAOA Backend class, for instance, `qaoa_circuit`, `get_counts` and so on. More formally, this class is responsible for converting the QAOA circuit from the OpenQAOA intermediate representation into the respective language supported by the `XYZ` hardware provider. Some template classes are defined in `openqaoa-core/openqaoa/backends/basebackends.py` that can be used as parent classes for this class. For instance, a QAOA Backend class implemeting a QPU that requires authentication, supports parametric circuit construction must inherit from `QAOABaseBackendShotBased`, `QAOABaseBackendCloud` and `QAOABaseBackendParametric`. + +## Recycling Backends from other plugins + +Sometimes, a hardware provider supports circuit construction and job execution via an already existing software framework, for example, `Qiskit`. In such a case, the backend plugin may import the `QAOAQiskitQPUBackend` class from the `openqaoa-qiskit` package to be used to support the new plugin instead of re-writing the whole class from scratch. Be sure to add `openqaoa-qiskit` as a requirement for the new plugin if this import is used. + +In an another situation, a backend may permit using `Qiskit` to define the circuit and then using some existing converters to transform the circuit into instructions parseable by the hardware. In such a case, the user may consider writing a new QAOA Backend class that inherits from the `QAOAQiskitQPUBackend` instead of the base-backend classes defined in `openqaoa-core`. diff --git a/docs/error-mitigation/spam-twirling.md b/docs/error-mitigation/spam-twirling.md new file mode 100644 index 0000000..f301cb7 --- /dev/null +++ b/docs/error-mitigation/spam-twirling.md @@ -0,0 +1,76 @@ +# SPAM Twirling + +!!! info "Note" + This feature is present only in openqaoa 0.1.4 and above! + + +State Preparation and Measurement (SPAM) Twirling is a simple error mitigation technique used to remove any preferred direction due to readout noise. It works by diagonalizing the noise associated with measurements by randomly flipping qubits via X gates right before the measurement and flipping the corresponding measured bit classically. +A calibration factor from the diagonal noise channel is obtained by measuring quantum circuits initialized in the zero states. As a result, the expectation values of the circuit in the presence of readout noise is much closer to the noise-free one. + +!!! info "For the curious" + The technique has been developed theoretically by E. v. d. Berg et al. [1] and by A. W. R. Smith, et al. [2] and implemented within Qiskit as one of their “resilience levels” under the name “Twirled Readout Error eXtinction (TREX)”. Experimentally has been applied by Layden et al. [3] to ensure that the symmetry requirement $Q(s'| s) = Q(s |s')$ is met. Note that this requirement is specific to the Monte Carlo algorithm and therefore irrelevant to QAOA. + + +### The algorithm +I. Obtain calibration data (ideally for the whole device) under the Bit Flipping Averaging (BFA) subroutine + +1. Initialize the circuit in the |000…0> state. +2. Measure under BFA (subroutine) +3. Save the counts and the registers (this is how the measurement string outcomes map to the physical qubits on the device) and all other relevant information to a json (see [the code](https://github.com/entropicalabs/openqaoa/blob/dev/tests/qpu_calibration_data/README_calibration_files.md) for the exact format). + +II. Run the quantum experiment under BFA + +1. Calculate calibration factors +2. Prepare the desired quantum circuit +3. Measure under BFA (subroutine) +4. Correct the expectation values by term +5. Combine all corrected terms into the final expectation value + +#### Subroutine: Bit Flip Averaging (BFA) technique + +1. Divide the total number of shots into $n$ batches and for each batch choose a set of qubits to be flipped. Note that since we usually don’t have a very accurate model of the noise and to keep it general, we choose the qubits within each batch uniformly at random. +2. The bit flip before the measurement can be done by applying an X gate, absorbing the X gate into the last layer of RX rotations or propagating it to the front (and then absorbing it into the initial |+> state). +3. The bit flip after the measurement is performed by applying a classical `not` to the outcome bitstring, which is implemented as changing the keys in the count dictionary. +4. Combine the negated counts from all batches into a single count dictionary which is then used for calculating the calibration factors or estimating the expectation values. + +Let's look at a simple example of a 2-qubit system for which the QAOA circuit is: +![circuit_original](/img/spam_twirling_circuit_0.png) + +Under BFA, every batch implements the desired QAOA circuit with single X gates prepended/appended randomly on a subset of the qubits. Considering,as an example, a simple two qubit circuit, there are 3 posibilities for the X gates. They can be applied to the first qubit +![circuit_XI](/img/spam_twirling_circuit_2.png) +to the second one +![circuit_IX](/img/spam_twirling_circuit_3.png) +or to both: +![circuit_XX](/img/spam_twirling_circuit_1.png) + +### How to do this within OpenQAOA? + +In the workflows, this can be implemented by simply doing: +```Python +q = QAOA() +q.set_error_mitigation_properties( + error_mitigation_technique="spam_twirling", + n_batches=4, + calibration_data_location="filename", +) +``` + +Internally, OpenQAOA modifies the backend object in order to divide the computation in batches and applies the conditional X gate on a set of qubits choosen uniformly at random +```Python +if error_mitigation_properties.error_mitigation_technique == 'spam_twirling': + backend = SPAMTwirlingWrapper(backend=self.backend, + n_batches=self.error_mitigation_properties.n_batches, + calibration_data_location=error_mitigation_properties.calibration_data_location) +``` + +### What to expect? +Let's see the technique in practice by solving MaxCut on a u3R graph for n=6 qubits. In this example, we simulate a 7 qubit device using the (noisy) Quantum Virtual MAchine, an emulator developed by Rigetti. We have a total of 1000 shots, we divided them into into 10 batches of equal number of shots (note that the number of batches and shots may be tweaked to improve the result!). + +![results_rigetti](/img/spam_twirling_results_rigetti.png) +The plot above shows a slice of the landscape at $\gamma=0.25$ and for various $\beta$. It is clear that by performing SPAM Twirling we obtain (the orange line) energies much closer to the theoretically simulated ones (dark blue line). + +## References +---------- +1. [Berg, E., Minev, Z. K., Temme, K.](https://journals.aps.org/pra/abstract/10.1103/PhysRevA.105.032620), Phys. Rev. A 105, 032620 (2022) +2. [Smith, A.W.R., Khosla, K.E., Self, C.N., Kim, M.S.](https://www.science.org/doi/10.1126/sciadv.abi8009), Science Advances, vol. 7, 47 (2021) +3. [Layden, D., Mazzola, G., Mishmash, R. V., Motta, M., Wocjan, P., Kim, J.-S., Sheldon, S.](https://arxiv.org/abs/2203.12497), arXiv:2203.12497, (see Appendix IV, sec.A2) diff --git a/docs/img/spam_twirling_circuit_0.png b/docs/img/spam_twirling_circuit_0.png new file mode 100644 index 0000000..d9af4a2 Binary files /dev/null and b/docs/img/spam_twirling_circuit_0.png differ diff --git a/docs/img/spam_twirling_circuit_1.png b/docs/img/spam_twirling_circuit_1.png new file mode 100644 index 0000000..b15e790 Binary files /dev/null and b/docs/img/spam_twirling_circuit_1.png differ diff --git a/docs/img/spam_twirling_circuit_2.png b/docs/img/spam_twirling_circuit_2.png new file mode 100644 index 0000000..b53864e Binary files /dev/null and b/docs/img/spam_twirling_circuit_2.png differ diff --git a/docs/img/spam_twirling_circuit_3.png b/docs/img/spam_twirling_circuit_3.png new file mode 100644 index 0000000..56928d1 Binary files /dev/null and b/docs/img/spam_twirling_circuit_3.png differ diff --git a/docs/img/spam_twirling_results_rigetti.png b/docs/img/spam_twirling_results_rigetti.png new file mode 100644 index 0000000..ecd1a34 Binary files /dev/null and b/docs/img/spam_twirling_results_rigetti.png differ diff --git a/docs/openqaoa-jobs/braket-container.md b/docs/openqaoa-jobs/braket-container.md new file mode 100644 index 0000000..8c6bfe3 --- /dev/null +++ b/docs/openqaoa-jobs/braket-container.md @@ -0,0 +1,28 @@ +# Bring your own OpenQAOA container to Amazon Braket Hybrid Jobs + +If you are wondering what is an Amazon Braket Hybrid Jobs, check out [Braket's very own answer](https://docs.aws.amazon.com/braket/latest/developerguide/braket-what-is-hybrid-job.html) + +> With Hybrid Jobs, you can run algorithms that use both classical and quantum compute resources. These hybrid quantum-classical algorithms can help you optimize the performance of the quantum devices currently available. These algorithms are designed to maximize the benefits and reduce the drawbacks of both types of computational systems and are generally used to find the ground state or global minimum of a particular system. + +QAOA is a great example of such hybrid quantum-classical algorithms, and we here provide a simple procedure to prepare your own OpenQAOA container. + +## Steps to create your own OpenQAOA container + +First of all, these instructions are based on Amazon Braket's documentation. Therefore, a safe place to check if you are an experienced Docker and AWS practitioner is to head to the [Bring your own container](https://docs.aws.amazon.com/braket/latest/developerguide/braket-jobs-byoc.html) page! + +The following instructions will allow you to create your OpenQAOA container. Note that they will work out of the box only for Linux and macOs. + + 1. Make sure all the dependencies are installed and credentials are properly set: + - Clone openqaoa from github `git clone https://github.com/entropicalabs/openqaoa.git` + - Install docker on your system + - Install the [AWS command line interface](https://aws.amazon.com/cli/) + - Create an Amazon Elastic Container Registry (Amazon ECR) repository (see step 3 [here](https://docs.aws.amazon.com/braket/latest/developerguide/braket-jobs-byoc.html)) + 2. Authenticate with AWS: to build the repository we first authenticate with AWS. We need to authenticate twice because we first need to download the Braket docker image which will be used as a base for building the OpenQAOA image, and a second time to upload the OpenQAOA image to your own ECR. + - Authenticate through the AWS command line interface: + - `docker login -u AWS -p $(aws ecr get-login-password --region ${REGION}) 292282985366.dkr.ecr.${REGION}.amazonaws.com`, this command is needed to download the base- + - `docker login -u AWS -p $(aws ecr get-login-password --region ${REGION}) ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com` + - Note that you will need to re-do this procedure for any `${REGION}` of interest, and you will also need to insert your own `$ACCOUNT_ID` +3. Build the image, and push it to the repository: + - Go to the OpenQAOA root folder and type `docker build -t ${REPOSITORY_NAME}`, where you can choose the tag you wish + - Then create an image tag (alias) with the full repository path for the ECR`docker tag ${REPOSITORY_NAME}:latest ${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${REPOSITORY_NAME}:latest` + - And finally push the image to: `${ACCOUNT_ID}.dkr.ecr.${REGION}.amazonaws.com/${REPOSITORY_NAME}:latest]` where all the names have been changed accordingly diff --git a/docs/optimizers/gradient-based-optimizers/gradient-computation.md b/docs/optimizers/gradient-based-optimizers/gradient-computation.md index f0fe201..c1cc6a6 100644 --- a/docs/optimizers/gradient-based-optimizers/gradient-computation.md +++ b/docs/optimizers/gradient-based-optimizers/gradient-computation.md @@ -44,7 +44,7 @@ q.optimize() ## Parameter-shift -The parameter-shift rule is a technique that allows for the exact computation of gradients for quantum circuits with certain gate sets. It works by exploiting the fact that the derivative of a unitary gate $U(\theta)$ with respect to its parameter $\theta$ can be expressed in terms of the gate itself, read XX. +The parameter-shift rule is a technique that allows for the exact computation of gradients for quantum circuits with certain gate sets. It works by exploiting the fact that the derivative of a unitary gate $U(\theta)$ with respect to its parameter $\theta$ can be expressed in terms of the gate itself, read [Schuld et al. (2018)](https://doi.org/10.1103/PhysRevA.99.032331). As a quick explanation, if we have a cost function like: @@ -120,7 +120,7 @@ The parameters are perturbed by a random vector that takes values of +1 or -1 wi $$ \vec\nabla f(\vec\gamma) \approx \frac{f(\vec\gamma + c \vec\Delta) - f(\vec\gamma - c \vec\Delta)}{2c} \odot \vec\Delta $$ -where $c$ is a constant that determines the step size, and $\vec\Delta$ is the perturbation vector: $\vec\Delta = (\delta_1, \delta_2, ..., \delta_n)$ where $ \delta_i \in \{-1, 1\}$ are randomly generated. +where $c$ is a constant that determines the step size, and $\vec\Delta$ is the perturbation vector: $\vec\Delta = (\delta_1, \delta_2, ..., \delta_n)$ where $\delta_i \in \{-1, 1\}$ are randomly generated. The primary benefit of Gradient SPSA is that it requires only two evaluations of the cost function to estimate the Jacobian, unlike the finite difference method, which requires two evaluations for each parameter. @@ -171,4 +171,4 @@ q.optimize() } }); } - \ No newline at end of file + diff --git a/docs/problems/knapsack.md b/docs/problems/knapsack.md index 4185a36..d3453bc 100644 --- a/docs/problems/knapsack.md +++ b/docs/problems/knapsack.md @@ -30,6 +30,7 @@ Now that we have an equality constraint, the corresponding QUBO formulation is r $$ C(\textbf{x}, \vec{y}) = -\sum_{i=0}^n v_i x_i + P\Big(\sum_{i=1}^n w_i x_i + \sum_{k=0}^k 2^i y_i- W\Big)^2, $$ + where $\textbf{x} = \{0,1\}^n, \ \ \vec{y} = \{0, 1\}^k$. This cost function can be converted in the form of an Ising formulation (so that variables take values in $\{-1, 1\}$) in order to be used with the QAOA algorithm (see [what-is-a-qubo](/problems/what-is-a-qubo)). diff --git a/docs/problems/minimum-vertex-cover.md b/docs/problems/minimum-vertex-cover.md index 2f017d1..3870606 100644 --- a/docs/problems/minimum-vertex-cover.md +++ b/docs/problems/minimum-vertex-cover.md @@ -5,11 +5,12 @@ The Minimum Vertex Cover (MVC) problem is a common constrained optimization prob ## The Cost Function The corresponding function to minimize can be derived as: + $$ C(\textbf{x}) = \sum_{i \in V}x_i + P\sum_{(i, j) \in E}\left(1-x_i\right)\left(1-x_j\right), $$ -where $\boldsymbol{x}\in \{0, 1\}^{|V|}$ and $P>1$ is a parameter controlling the strength of penalization of configurations which are not covers. +where $\textbf{x}\in \{0, 1\}^{|V|}$ and $P>1$ is a parameter controlling the strength of penalization of configurations which are not covers. Interpreting a variable $x_i$ being equal to 1 as being part of the vertex cover, the first summation counts the size of the selected cover while the second summation ensures that the selected cover indeed covers all edges. Hence, minimizing it ensures we find the minimum vertex cover. diff --git a/docs/problems/number-partition.md b/docs/problems/number-partition.md index f999cc7..82f6f13 100644 --- a/docs/problems/number-partition.md +++ b/docs/problems/number-partition.md @@ -11,9 +11,9 @@ For example, given the set of numbers $S=\{1, 2, 3, 6, 10\}$, one can find that The function to minimize can be defined as -$$C(\sigma) = \left(\sum_{i=1}^k n_i\sigma_i\right)^2 = \sum_{i, j=1}^kn_in_j\sigma_i\sigma_j,$$ +$$C(\textbf{\sigma}) = \left(\sum_{i=1}^k n_i\sigma_i\right)^2 = \sum_{i, j=1}^kn_in_j\sigma_i\sigma_j,$$ -where $\sigma \in \{-1, 1\}^k$. That is, a variable $\sigma_i$ is attached to each number $n_i$, and the variable's value determines on which side of the partition the number is assigned to. The smallest value $C(\cdot)$ can take is 0, which happens when $\sigma$ is a perfect partition. +where $\textbf{\sigma}\in \{-1, 1\}^k$. That is, a variable $\sigma_i$ is attached to each number $n_i$, and the variable's value determines on which side of the partition the number is assigned to. The smallest value $C(\cdot)$ can take is 0, which happens when $\textbf{\sigma}$ is a perfect partition. Since this formulation is already in terms of Ising variables, it can be used directly in QAOA. diff --git a/mkdocs.yml b/mkdocs.yml index 045ada4..b9b32e3 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -124,7 +124,7 @@ nav: - optimizers/gradient-free-optimizers.md - optimizers/pennylane-optimizers.md - optimizers/shot-adaptive-optimizers.md - - The Devices: + - Devices: - devices/device.md - Local Simulators: - devices/qiskit.md @@ -138,6 +138,12 @@ nav: - devices/rigetti-qcs.md - Qubit Routing: - qubit-routing/qaoa-qubit-routing.md + - Error Mitigation: + - error-mitigation/spam-twirling.md + - OpenQAOA jobs: + - openqaoa-jobs/braket-container.md + - Contributing: + - contributing/add_new_backend.md - Challenges: - challenges/intro.md - Events: