CUAOA is a GPU accelerated QAOA simulation framework utilizing the NVIDIA CUDA toolkit. This framework offers a complete interface for QAOA simulations, enabling the calculation of (exact) expectation values, direct access to the statevector, fast sampling, and high-performance optimization methods using an advanced state-of-the-art gradient calculation technique. The framework is designed for use in Python and Rust, providing flexibility for integration into a wide range of applications, including those requiring fast algorithm implementations leveraging QAOA at its core.
To streamline the installation of our project, utilize the install.sh
script. This script automates the process by cloning the repository, building the project, and installing it on your system.
We plan to make CUAOA installable via pip in the upcoming future.
Before proceeding with the installation, ensure the following tools are installed on your system:
- Rust and Cargo: Required to compile the Rust libraries.
- g++: Required to compile the C++ library.
- CUDA and nvcc: Required for CUDA-accelerated computations and the compilation.
- git: Required for cloning the repository.
- pip: Necessary for Python package installations.
- conda: A crucial tool for environment and package management.
- Python >= 3.11: Required for running the Python code. Other versions may work but have not been tested.
Important
The installation script must be run within an active conda
environment tailored for this project. If such an environment is not yet set up, follow these instructions to create and activate one:
# Create a new conda environment
conda create -n your-env-name python=3.11
# Activate the conda environment
conda activate your-env-name
Replace your-env-name
with a desired name for your conda environment.
Within the activated conda
environment, the script will install the following essential packages:
custatevec
: A library for state vector manipulation in CUDA,lbfgs
: An implementation of the L-BFGS optimization algorithm in C.
Make sure to read and understand the license of cuStateVec
prior to running the installation script.
To initiate the installation, execute the following command in your terminal:
./install.sh
For a more detailed output during the installation process, include the --verbose
option:
./install.sh --verbose
Caution
Running scripts directly from the internet poses a risk. It is recommended to first download and review the script before execution:
# Review the script's contents
less install.sh
# Execute the script after review
bash install.sh
To provide an alternative installation method using Docker, follow the steps below to build and run the CUAOA application within a Docker container.
This section guides you through building the Docker image and running the CUAOA application in a container.
- Ensure that Docker is installed on your system. You can download it from the official Docker website.
- Verify that your system has an NVIDIA GPU and that the NVIDIA Container Toolkit is installed to enable GPU support within Docker containers.
Open a terminal and navigate to the root directory of the CUAOA project. Then, execute the following command to build the Docker image:
docker buildx build --tag cuaoa-image --load .
This command uses Docker Buildx to build the image and tags it as cuaoa-image
.
After successfully building the image, run the following command to start a container:
docker run --rm -it --gpus all cuaoa-image
This command runs the cuaoa-image
container interactively with access to all available GPUs.
Parameters Explained:
--rm
: Automatically removes the container when it exits. This option is optional but helps prevent clutter from stopped containers.-it
: Allocates a pseudo-TTY and keeps STDIN open, allowing interactive terminal access.--gpus all
: Grants the container access to all available GPU devices.
For more detailed information on these and other Docker run options, please refer to the Docker CLI documentation.
By following these steps, you can build and run the CUAOA application within a Docker container, leveraging your system's GPU resources.
Tip
If you encounter any issues during installation:
- Double-check the prerequisites to ensure all necessary tools are installed.
- Verify that the
conda
environment is activated before running the installation script. - Review permissions if encountering errors related to script execution. Adjusting script permissions with
chmod +x install.sh
may be required.
For further assistance, please visit our Issues page and describe the problem you're facing. We are committed to providing support and resolving installation queries.
With CUAOA installed, you can start simulating QAOA. The essential steps for a simulation are:
- Define the objective and convert it to one of the expected formats.
- Create the handle required for interactions with the simulator.
- Create the CUAOA class to access the simulator's functionality.
First, we define a simple MaxCut problem and use it throughout this usage guide. We will focus on creating the problem from the graph's adjacency matrix.
import numpy as np
import pycuaoa
W = np.array([[0.0, 1.0, 0.0], [1.0, 0.0, 1.0], [0.0, 1.0, 0.0]])
# Initialize the CUAOA class with the optimization problem.
# For further initialization options, please refer to the CUAOA interface.
sim = pycuaoa.CUAOA(W, depth=2)
# Create the handle for interactions with the simulator. We must specify the minimum
# number of qubits required during the simulations using the given handle.
# As the current MaxCut problem consists of 3 nodes, we set this value to 3.
# Setting it to a higher value than needed will not affect the correctness of the
# simulations but will consume more memory.
num_qubits = 3
handle = pycuaoa.create_handle(num_qubits)
expectation_value = sim.expectation_value(handle) # Calculate the expectation value.
print(expectation_value)
# -1.3724677
sv = sim.statevector(handle) # Retrieve the state vector.
print(sv)
sampleset = sim.sample(handle, num_shots=1) # Obtain samples.
# The sampling process can also be seeded using the `seed` parameter:
# sampleset = sim.sample(handle, num_shots=1, seed=...)
# To access the samples in the sample set, use:
samples = sampleset.samples()
print(samples)
# [[False True True]]
# The objective value associated with each sample set can be accessed with:
costs = sampleset.energies()
print(costs)
# [-1]
gradients, ev = sim.gradients(handle) # Calculate the gradients.
# Calculating the gradients will also compute the respective expectation value.
# You can also calculate the gradients for a given set of parameters with:
# gradients, ev = sim.gradients(
# handle,
# betas=np.array([0.0, 1.0]),
# gammas=np.array([0.4, 1.3])
# )
# To access the gradients, you can use:
print(gradients.betas)
# [ 0.52877299 -0.86224096]
print(gradients.gammas)
# [-0.35863235 -0.50215632]
optimize_result = sim.optimize(
handle
) # Optimize the parameters using the built-in optimizer.
# This runs the optimization with default parameters. You can also control the
# optimization by passing a `pycuaoa.LBFGSParameters` object, for example:
# optimize_result = sim.optimize(
# handle,
# lbfgs_parameters=pycuaoa.LBFGSParameters(max_iterations=10)
# )
# The optimized parameters are automatically set in the `sim` object but can be
# accessed with:
# `optimize_result.parameters.betas` and
# `optimize_result.parameters.gammas`.
# We can now recalculate the expectation value to see the effect:
expval_after_optimization = sim.expectation_value(handle)
print(expval_after_optimization)
# -1.99999999
# Sampling after optimization now also gives us the expected results:
sampleset_after_optimization = sim.sample(handle, num_shots=1)
print(sampleset_after_optimization.samples())
# array([[False, True, False]])
To use CUAOA
with an arbitrary optimization problem, you can use the from_map
function. For example, for the MaxCut problem used in the previous example:
terms = {
(0, 1): 2.0, (1, 2): 2.0,
(0,): -1.0, (1,): -2.0, (2,): -1.0
}
sim = pycuaoa.CUAOA.from_map(num_qubits, terms, depth=2)
The remaining interactions with the sim
object remain the same.
To release the allocated memory you can use the .destory()
method on the handle:
handle.destroy()
This project is licensed under the Apache License 2.0. See the LICENSE file for details.
By using this software, you agree to comply with the licenses of all dependencies used in this project. Notably, the cuStateVec
library has its own licensing terms which must be adhered to.
If you use this software, please cite it as follows:
@misc{stein2024cuaoanovelcudaacceleratedsimulation,
title={CUAOA: A Novel CUDA-Accelerated Simulation Framework for the QAOA},
author={Jonas Stein and Jonas Blenninger and David Bucher and Josef Peter Eder and Elif Çetiner and Maximilian Zorn and Claudia Linnhoff-Popien},
year={2024},
eprint={2407.13012},
archivePrefix={arXiv},
primaryClass={quant-ph},
url={https://arxiv.org/abs/2407.13012},
}
@software{blen_CUAOA_2024,
author={Blenninger, Jonas and
Stein, Jonas and
Bucher, David and
Eder, Peter J. and
Çetiner, Elif and
Zorn, Maximilian and
Linnhoff-Popien, Claudia},
title={{CUAOA: A Novel CUDA-Accelerated Simulation Framework for the QAOA}},
month=jul,
year=2024,
publisher={Zenodo},
version={0.1.0},
doi={10.5281/zenodo.12750207},
url={https://doi.org/10.5281/zenodo.12750207}
}