A flexible, modular Python library for the Quantum Approximate Optimization Algorithm / Quantum Alternating Operator Ansatz (QAOA), designed for research and experimentation. Swap problems, mixers, initial states, optimizers, and backends without rewriting your code.
- Installation
- Requirements
- Quick Example
- Background
- Custom Ansatz
- Running Optimization
- Further Parameters
- Extracting Results
- Multi-Angle QAOA
- Building Circuits like Lego
- Minimizing Circuit Depth
- Repository Structure
- Agent
- Citation
- Acknowledgement
pip install qaoaOr install in development mode from source:
git clone https://github.com/OpenQuantumComputing/QAOA.git
cd QAOA
pip install -e .- Python ≥ 3.9
- qiskit ≥ 2.3.0
- qiskit-aer ≥ 0.17.0
- qiskit-algorithms ≥ 0.4.0
- numpy, scipy, matplotlib, networkx
Optional (for the agent):
- langchain, langchain_community, langchain_chroma, langchain_openai, streamlit
import networkx as nx
from qaoa import QAOA, problems, mixers, initialstates
# Build a random graph
G = nx.random_regular_graph(3, 8, seed=42)
# Define QAOA components
qaoa = QAOA(
problem=problems.MaxCut(G),
mixer=mixers.X(),
initialstate=initialstates.Plus()
)
# Sample cost landscape at depth p=1
qaoa.sample_cost_landscape()
# Optimize to depth p=3
qaoa.optimize(depth=3)
# Extract results
print("Optimal expectation value:", qaoa.get_Exp(depth=3))
print("Optimal parameters (gamma):", qaoa.get_gamma(depth=3))
print("Optimal parameters (beta):", qaoa.get_beta(depth=3))See examples/ for more complete worked examples.
Given a cost function
which means that ground states minimize the cost function
QAOA of depth
where
-
$U_P$ is a family of phase-separating operators, -
$U_M$ is a family of mixing operators, and -
$|s\rangle$ is a "simple" initial state.
In plain vanilla QAOA these have the form
To create a custom QAOA ansatz, specify a problem, a mixer, and an initial state. These base classes each have an abstract method def create_circuit: that must be implemented. The problem base class additionally requires def cost:.
This library already contains several standard implementations.
- The following problem cases are already available:
- The following mixer cases are already available:
- X-mixer
- XY-mixer
- Grover-mixer
- Max k-CUT grover
- Max k-CUT LX
- X multi-angle mixer (one β per qubit)
- The following initial state cases are already available:
- Plus
- Statevector
- Dicke
- Dicke 1- and 2-states superposition
- Less than k
- Max k-CUT feasible
- Plus parameterized (|+⟩ with optimizable phase rotations)
It is very easy to extend this list by implementing the abstract methods of the base classes above. Feel free to fork the repo and open a pull request!
For example, to set up QAOA for MaxCut using the X-mixer and
qaoa = QAOA(
problem=problems.MaxCut(G),
mixer=mixers.X(),
initialstate=initialstates.Plus()
)For depth
qaoa.sample_cost_landscape()Sampling high-dimensional target functions quickly becomes intractable for depth
- At depth
$p=1$ : parameters$(\gamma, \beta)$ are taken from the minimum of the sampled cost landscape. - At depth
$p>1$ : parameters are seeded via an interpolation-based heuristic from the optimal values at the previous depth.
qaoa.optimize(depth=p)This will call sample_cost_landscape automatically if it has not been run yet.
qaoa = QAOA(
...,
backend=,
noisemodel=,
optimizer=,
precision=,
shots=,
cvar=
)-
backend: the backend to use, defaults toAerSimulator()fromqiskit_aer -
noisemodel: noise model to apply, defaults toNone -
optimizer: optimizer from qiskit-algorithms with options, defaults to[COBYLA, {}] -
precision: sample until a certain precision of the expectation value is reached, based on$\text{error}=\frac{\text{variance}}{\sqrt{\text{shots}}}$ , defaults toNone -
shots: number of measurement shots, defaults to1024 -
cvar: value for Conditional Value at Risk (CVaR), defaults to1(standard expectation value)
Once qaoa.optimize(depth=p) is run, extract the expectation value, variance, and parameters for each depth
qaoa.get_Exp(depth=i)
qaoa.get_Var(depth=i)
qaoa.get_gamma(depth=i)
qaoa.get_beta(depth=i)Additionally, for every optimizer call at each depth, the angles, expectation value, variance, maximum cost, minimum cost, and number of shots are stored in:
qaoa.optimization_results[i]Multi-angle QAOA allows components to use multiple parameters per layer, increasing expressibility:
- Multi-angle mixer (
XMultiAngle): each qubit gets its own independent β parameter. - Parameterized initial state (
PlusParameterized): the initial state |+⟩ with optimizable per-qubit phase rotations.
qaoa = QAOA(
problem=problems.MaxCut(G),
mixer=mixers.XMultiAngle(), # N_qubits beta parameters per layer
initialstate=initialstates.Plus()
)The flat angle array format used by hist(), getParametersToBind(), and interp() is:
[init_0, ..., init_{n-1}, # initial state params (0 for Plus)
gamma_{0,0}, ..., beta_{0,n-1}, # layer 0 params
gamma_{1,0}, ..., beta_{1,n-1}, # layer 1 params
...]
For the standard single-parameter case this reduces to [gamma_0, beta_0, gamma_1, beta_1, ...].
Implement get_num_parameters() in a custom component to enable multi-angle support. See examples/MultiAngle for a complete example.
Assuming all-to-all connectivity of qubits, one can minimize the circuit depth of the phase separating operator by solving the minimum edge colouring problem. This is implemented in GraphHandler and is invoked automatically. An example output is shown below:
Components can be freely composed ("lego style") to build more complex circuits.
A typical workflow is:
- Define a feasible-state preparation circuit (e.g. Dicke).
- Build a mixer acting on that feasible space (e.g. Grover).
- Replicate the resulting block across independent registers using a tensor product.
For example, construct a Dicke state with Hamming weight
from qaoa import initialstates, mixers
dicke = initialstates.Dicke(2, 4) # k=2 excitations on N=4 qubitsNext, build a Grover mixer that operates on the feasible space prepared by the Dicke circuit:
grover = mixers.Grover(dicke)
grover.create_circuit()
grover.circuit.draw('mpl')The Grover mixer implements
where Dicke / Dicke†).
Finally, use Tensor to replicate the block across independent registers:
tensor = initialstates.Tensor(grover, 3) # 3 copies → 12 qubits total
tensor.create_circuit()
tensor.circuit.draw('mpl')The Grover mixer automatically inherits the qubit count from the Dicke circuit, and Tensor replicates the full block without manual qubit bookkeeping.

Lego-like circuit: three Grover blocks on 12 qubits
Every component (initial state or mixer) carries a label attribute used as the circuit name when create_circuit() is called. The label defaults to the class name but can be customised at construction time (for Dicke, Grover, and Tensor) or by setting the attribute before calling create_circuit():
dicke = initialstates.Dicke(2, 4, label="Dicke-2")
dicke.create_circuit()
print(dicke.circuit.name) # → "Dicke-2"
xy = mixers.XY()
xy.label = "XY-ring"
xy.setNumQubits(4)
xy.create_circuit()
print(xy.circuit.name) # → "XY-ring"QAOA/
├── qaoa/ # Core library
│ ├── qaoa.py # Main QAOA class
│ ├── problems/ # Problem Hamiltonians (MaxCut, QUBO, Portfolio, …)
│ ├── mixers/ # Mixing operators (X, XY, Grover, …)
│ ├── initialstates/ # Initial state circuits (Plus, Dicke, Tensor, …)
│ └── util/ # Graph utilities and helpers
├── examples/ # Jupyter notebook examples
│ ├── MaxCut/
│ ├── ExactCover/
│ └── PortfolioOptimization/
├── agent/ # LLM-powered QAOA assistant
├── unittests/ # Unit tests
├── images/ # Figures used in documentation
└── setup.py
The agent/ folder contains a specialized QAOA assistant that can answer questions about the library or generate example code.
Run from the terminal:
cd agent
python planner.pyRun as a web interface:
cd agent
streamlit run interface.pyExample interaction:
Dependencies for the agent: langchain, langchain_community, langchain_chroma, langchain_openai, and optionally streamlit for the web interface. An OpenAI API key is also required.
If you use this library in your research, please cite:
@software{fuchs2024qaoa,
author = {Franz Georg Fuchs},
title = {{QAOA}: A Modular Python Library for the Quantum Approximate Optimization Algorithm},
year = {2024},
url = {https://github.com/OpenQuantumComputing/QAOA},
note = {Version 1.2.3}
}This work was funded by the Research Council of Norway through project number 33202.




