qml.RotosolveOptimizer

class RotosolveOptimizer[source]

Bases: object

Rotosolve gradient free optimizer.

The Rotosolve optimizer minimizes an objective function with respect to the parameters of a quantum circuit without the need for calculating the gradient of the function. The algorithm works by updating the parameters \(\theta = \theta_1, \dots, \theta_D\) one at a time according to a closed-form expression for the optimal value of the \(d^{th}\) parameter \(\theta^*_d\) when the other parameters are fixed:

\[\theta^*_d = \underset{\theta_d}{\text{argmin}}\left<H\right>_{\theta_d} = -\frac{\pi}{2} - \text{arctan2}\left(2\left<H\right>_{\theta_d=0} - \left<H\right>_{\theta_d=\pi/2} - \left<H\right>_{\theta_d=-\pi/2}, \left<H\right>_{\theta_d=\pi/2} - \left<H\right>_{\theta_d=-\pi/2}\right),\]

where \(\left<H\right>_{\theta_d}\) is the expectation value of the objective function optimized over the parameter \(\theta_d\). \(\text{arctan2}(x, y)\) computes the element-wise arc tangent of \(x/y\) choosing the quadrant correctly, avoiding, in particular, division-by-zero when \(y = 0\).

The algorithm is described in further detail in Ostaszewski et al. (2019)

Example:

Initialize the optimizer, set the initial values of x to be used and set the number of steps to optimize over.

>>> opt = qml.optimize.RotosolveOptimizer()
>>> x = [0.3, 0.7]
>>> n_steps = 1000

Set up the PennyLane circuit using the default.qubit as simulator device.

>>> dev = qml.device("default.qubit", analytic=True, wires=2)
... @qml.qnode(dev)
... def circuit(params):
...     qml.RX(params[0], wires=0)
...     qml.RY(params[1], wires=1)
...     qml.CNOT(wires=[0, 1])
...     return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliY(1))

Define a cost function (that takes a list of values as input and return a single value) based on the above circuit.

>>> def cost(x):
...     X_1, Y_2 = circuit(x)
...     return 0.2 * X_1 + 0.5 * Y_2

Run the optimization step-by-step for n_steps steps.

>>> cost_rotosel = []
>>> for _ in range(n_steps):
...     cost_rotosel.append(cost(x))
...     x = opt.step(cost, x)

The optimized values for x should now be stored in x and steps-vs-cost can be seen by plotting cost_rotosel.

step(objective_fn, x)

Update x with one step of the optimizer.

step(objective_fn, x)[source]

Update x with one step of the optimizer.

Parameters
  • objective_fn (function) – The objective function for optimization. It should take a sequence of the values x and a list of the gates generators as inputs, and return a single value.

  • x (Union[Sequence[float], float]) – Sequence containing the initial values of the variables to be optimized over, or a single float with the initial value.

Returns

The new variable values \(x^{(t+1)}\).

Return type

array

Contents

Using PennyLane

Development

API