## `eigenkit.core.optimizers`

Optimisers that need no gradient, for objectives that are noisy and expensive.

`spsa` implements Simultaneous Perturbation Stochastic Approximation (SPSA) (Spall 1992). It estimates the gradient from two evaluations of the objective per iteration, whatever the number of parameters. This is why it is the usual choice when every evaluation is a whole kernel matrix or a paid job on hardware. It uses only NumPy.

Example

```python
import numpy as np
from eigenkit.core.optimizers import spsa

result = spsa(lambda x: float(np.sum((x - 1.0) ** 2)), np.zeros(3), maxiter=200)
print(np.round(result.x, 1))   # [0.9 0.9 0.9]
```

### `SPSAResult`

Outcome of spsa().

Attributes:

| Name            | Type                | Description                                                                   |
| --------------- | ------------------- | ----------------------------------------------------------------------------- |
| `x`             | `ndarray`           | The final parameters.                                                         |
| `fun`           | `float`             | The value of the objective at x.                                              |
| `n_iterations`  | `int`               | The number of iterations run.                                                 |
| `n_evaluations` | `int`               | The number of evaluations of the objective, including the one at the final x. |
| `history`       | `tuple[float, ...]` | The value of the objective after every iteration, in order.                   |
| `success`       | `bool`              | Whether the final value of the objective is lower than the starting value.    |
| `initial_fun`   | `float`             | The value of the objective at x0.                                             |
| `best_x`        | \`ndarray           | None\`                                                                        |
| `best_fun`      | `float`             | The value of the objective at best_x.                                         |

### `spsa(fun, x0, *, maxiter=100, learning_rate=0.05, perturbation=0.05, alpha=0.602, gamma=0.101, random_state=0, callback=None)`

Minimise `fun` with Simultaneous Perturbation Stochastic Approximation (SPSA).

Each iteration draws a random direction `delta` with entries `±1`, evaluates `fun` at `x ± c_k * delta`, and takes a step against the resulting estimate of the gradient. The step size and the perturbation size decrease as `a / (k + 1) ** alpha` and `c / (k + 1) ** gamma`, with the standard exponents of Spall.

Parameters:

| Name            | Type                                      | Description                                                           | Default                                                                                                                                                                                                                               |
| --------------- | ----------------------------------------- | --------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `fun`           | `Callable[[ndarray], float]`              | The objective to minimise. It maps a 1-D parameter vector to a float. | *required*                                                                                                                                                                                                                            |
| `x0`            | `ndarray`                                 | The starting parameters.                                              | *required*                                                                                                                                                                                                                            |
| `maxiter`       | `int`                                     | The number of iterations to run.                                      | `100`                                                                                                                                                                                                                                 |
| `learning_rate` | \`float                                   | None\`                                                                | The initial step size a. None calibrates it from a few gradient estimates at x0, so that the first step moves the parameters by about 2π / 10, as the SPSA of qiskit-algorithms does. These evaluations are counted in n_evaluations. |
| `perturbation`  | `float`                                   | The initial perturbation size c.                                      | `0.05`                                                                                                                                                                                                                                |
| `alpha`         | `float`                                   | The exponent with which the step size decreases.                      | `0.602`                                                                                                                                                                                                                               |
| `gamma`         | `float`                                   | The exponent with which the perturbation size decreases.              | `0.101`                                                                                                                                                                                                                               |
| `random_state`  | \`int                                     | None\`                                                                | The seed for the perturbation directions.                                                                                                                                                                                             |
| `callback`      | \`Callable\[[int, ndarray, float], None\] | None\`                                                                | A function called after every iteration as callback(iteration, x, fun(x)).                                                                                                                                                            |

Returns:

| Type         | Description                                                                                                                                |
| ------------ | ------------------------------------------------------------------------------------------------------------------------------------------ |
| `SPSAResult` | An SPSAResult. The evaluations for the history are extra calls to fun, made so that the run can be plotted, and n_evaluations counts them. |
