Source and attribution
This notebook is a marimo/Aqora port of Quantinuum's
Solving the Max-Cut Problem with QAOA
Jupyter tutorial. The original tutorial and code belong to Quantinuum
and their respective authors. This port preserves the tutorial's structure
while adapting the notebook format and Guppy execution path for
guppylang==0.21.16. It is not an official Quantinuum or Aqora publication.
Aqora compatibility note. The original Guppy v1.x tutorial fixes the graph topology and number of layers at compile time while passing the cost and mixer angles as runtime arguments. Inguppylang==0.21.16, the Selene emulator entrypoint used here must take no arguments. This port therefore embeds the angles withcomptimeand rebuilds the small program for each optimizer evaluation. The QAOA circuit and objective remain unchanged.
QsysResult object after our circuit is processed by the Selene simulator. We do this with the energy_from_result function below. Note that the fact that the max-cut problem Hamiltonian contains only commuting terms means that we do not need to calculate our energy expectation using multiple measurement circuits.build_qaoa_program instead defines a zero-argument main entrypoint with the supplied angles embedded as compile-time constants. run_qaoa_circuit builds and executes that program with Selene, and eval_qaoa_energy turns the result into the scalar energy needed by the classical optimizer.
The p_value argument defines the number of cost/mixer layers in the QAOA program.eval_qaoa_energy function which does a single "forward pass" of our algorithm, we can use a classical optimizer to find a set of parameters which maximizes the energy expectation value.
To accomplish this, we define a SciPy objective function that accepts a single parameter vector, splits it into QAOA cost and mixer coefficients, builds and evaluates the Guppy program for those coefficients, and returns the negative energy. Minimizing the negative energy is equivalent to maximizing the max-cut energy.
Now we can put all of this machinery together in a solve_max_cut_instance function which, given a graph, attempts to solve the max-cut problem using this variational method. After the optimizer finishes, we run one final QAOA forward pass with the best parameters and use that QsysResult for validation and plotting.
Our function takes the following arguments:
graph: A networkx graph for which we want to solve the max-cut problem.max_optimizer_iterations: The maximum number of objective evaluations in the SciPy optimizer.p_value: The number of alternating cost/mixer layers in our QAOA program.n_shots: The number of Guppy program executions for each expectation value calculation.seed: A seed for the random number generator so the initial parameters and emulator executions are reproducible.-cost_angle * pi / 2, and the mixer layer applies mixer_angle * pi. The optimizer works directly with these real-valued coefficients.
Aqora usability note. The helper accepts an optionalprogress_interval. The tutorial run below reports one line every five objective evaluations so a long-running remote calculation visibly remains active. Set it toNonefor the original silent behavior.
Rx gates. See the build_qaoa_instance function.maxiter budget was exhausted.
The optimizer objective above maximizes the expected max-cut energy. This is related to, but not identical to, maximizing the probability of sampling one of the two exact optimal colorings.