## `eigenkit.optimization.qaoa`

The Quantum Approximate Optimization Algorithm (QAOA) with the core of the library.

It builds the standard QAOA ansatz from the qubit Hamiltonian of a problem, optimises the angles `(γ, β)` with `minimize_expectation`, and then reads the distribution of bitstrings of the optimised state (`probabilities`) to find a solution. It uses only NumPy and SciPy, needs no PyTorch, and works with any backend that can return the probabilities of the basis states.

## `eigenkit.optimization.qaoa.QAOA`

Bases: `BaseQuantumSolver`

The Quantum Approximate Optimization Algorithm (QAOA) solver.

It solves an `Ising` or `QUBO` problem.

Parameters:

| Name           | Type           | Description                                                                                        | Default                                                                             |
| -------------- | -------------- | -------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| `layers`       | `int`          | The depth p of QAOA. Default: 1.                                                                   | `1`                                                                                 |
| `provider`     | `ProviderSpec` | The backend. Default: "numpy", the reference NumPy simulator.                                      | `'numpy'`                                                                           |
| `optimizer`    | `Optimizer`    | A SciPy method name, "spsa", or a custom callable (see minimize_expectation). Default: "L-BFGS-B". | `'L-BFGS-B'`                                                                        |
| `random_state` | \`int          | None\`                                                                                             | The seed of the random initial angles. With None, they are not seeded. Default: 42. |

### `solve(problem, *, initial_parameters=None, top_k=None, **minimize_kwargs)`

Optimise the QAOA angles and read the answer from the final state.

Parameters:

| Name                 | Type      | Description                                                                          | Default                                                                                                                                                                                                                                                              |
| -------------------- | --------- | ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `problem`            | \`QUBO    | Ising\`                                                                              | The problem to minimise.                                                                                                                                                                                                                                             |
| `initial_parameters` | \`ndarray | None\`                                                                               | The initial angles γ and β, of shape (2 * layers,). They are random when they are not given. Default: None.                                                                                                                                                          |
| `top_k`              | \`int     | None\`                                                                               | How many of the most probable bitstrings to score with the energy of the problem. The best of them is returned as best_bitstring, and the others are not returned. Default: None, which scores the 64 most probable bitstrings, or all of them when there are fewer. |
| `**minimize_kwargs`  | `Any`     | Other keyword arguments, passed to minimize_expectation, for example max_iterations. | `{}`                                                                                                                                                                                                                                                                 |

Returns:

| Type                 | Description                                                                           |
| -------------------- | ------------------------------------------------------------------------------------- |
| `OptimizationResult` | An OptimizationResult with the best bitstring, its energy and the final distribution. |

Raises:

| Type         | Description                 |
| ------------ | --------------------------- |
| `ValueError` | If top_k is smaller than 1. |

## `eigenkit.optimization.qaoa.OptimizationResult`

Bases: `ValueEquality`

The result of a run of the Quantum Approximate Optimization Algorithm (QAOA).

The result is read-only. Assigning to a field raises `FrozenInstanceError`, and writing into an array field raises `ValueError`. This prevents a mistyped `=` (instead of `==`) or an in-place edit from leaving a result whose scalar fields describe a different run from the arrays it holds. To get a writable copy of an array, use `np.array(result.field)`.

Results compare by value, including their arrays. They are not hashable, because a result is a collection of numbers and not a key, and a correct hash of a float array is expensive to compute.

Attributes:

| Name                 | Type              | Description                                                                                                                         |
| -------------------- | ----------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `best_bitstring`     | `tuple[int, ...]` | The configuration with the lowest energy that was found, as a tuple of bits.                                                        |
| `best_energy`        | `float`           | Its energy for the problem being solved. This is the answer to report: QAOA samples, so the best sample is better than the average. |
| `expectation`        | `float`           | The mean energy of the final state. Compare it with best_energy to see how concentrated the distribution is.                        |
| `optimal_parameters` | `ndarray`         | The angles γ and β that the optimiser settled on.                                                                                   |
| `probabilities`      | `ndarray`         | The probability of every basis state, of length 2\*\*n.                                                                             |
| `n_iterations`       | `int`             | The number of iterations of the optimiser.                                                                                          |
| `success`            | `bool`            | Whether the optimiser reported convergence.                                                                                         |

### `__post_init__()`

Make the array fields read-only.

Freezing the dataclass prevents a field from being reassigned, but it does not prevent writing into the array that the field holds, and a result that has been written into still reports the scalar values of the original run. The result therefore keeps its own copies, so the arrays it was built from can still be changed by the caller. To get a writable copy, use `np.array(result.optimal_parameters)`.

## `eigenkit.optimization.qaoa.qaoa_ansatz(hamiltonian, num_qubits, layers)`

Build the standard QAOA circuit.

QAOA is the Quantum Approximate Optimization Algorithm. The circuit starts in `|+⟩^n`, then applies `layers` repetitions of the cost unitary `exp(-i γ_l H_C)` and the mixer `exp(-i β_l Σ_i X_i)`. It has `2 * layers` weights, in the order `[γ_0, β_0, γ_1, β_1, ...]`.

Parameters:

| Name          | Type         | Description                                                                        | Default    |
| ------------- | ------------ | ---------------------------------------------------------------------------------- | ---------- |
| `hamiltonian` | `Observable` | The cost Hamiltonian.                                                              | *required* |
| `num_qubits`  | `int`        | The number of qubits, one per variable.                                            | *required* |
| `layers`      | `int`        | The depth of QAOA, which is the number of pairs of a cost layer and a mixer layer. | *required* |

Returns:

| Type          | Description                                                    |
| ------------- | -------------------------------------------------------------- |
| `CircuitSpec` | The ansatz, as a CircuitSpec with 2 * layers trainable angles. |
