# qml.RotosolveOptimizer¶

class RotosolveOptimizer[source]

Bases: object

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 = 10


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, wires=0)
...     qml.RY(params, wires=1)
...     qml.CNOT(wires=[0, 1])
...     return qml.expval(qml.PauliZ(0)), qml.expval(qml.PauliX(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):
...     Z_1, X_2 = circuit(x)
...     return 0.2 * Z_1 + 0.5 * X_2


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

>>> cost_rotosolve = []
>>> for _ in range(n_steps):
...     cost_rotosolve.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