class RotoselectOptimizer(possible_generators=None)[source]

Bases: object

Rotoselect gradient-free optimizer.

The Rotoselect optimizer minimizes an objective function with respect to the rotation gates and 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\) and rotation gate choices \(R = R_1,\dots,R_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 and gate choices 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\).

Which parameters and gates that should be optimized over is decided in the user-defined cost function, where \(R\) is a list of parametrized rotation gates in a quantum circuit, along with their respective parameters \(\theta\) for the circuit and its gates. Note that the number of generators should match the number of parameters.

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


possible_generators (list[Operation]) – List containing the possible pennylane.ops.qubit operators that are allowed in the circuit. Default is the set of Pauli rotations \(\{R_x, R_y, R_z\}\).


Initialize the Rotoselect optimizer, set the initial values of the weights x, choose the initial generators, and set the number of steps to optimize over.

>>> opt = qml.optimize.RotoselectOptimizer()
>>> x = [0.3, 0.7]
>>> generators = [qml.RX, qml.RY]
>>> n_steps = 1000

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

>>> dev = qml.device("default.qubit", analytic=True, wires=2)
>>> @qml.qnode(dev)
... def circuit(params, generators=None):  # generators will be passed as a keyword arg
...     generators[0](params[0], wires=0)
...     generators[1](params[1], wires=1)
...     qml.CNOT(wires=[0, 1])
...     return qml.expval(qml.PauliX(0)), qml.expval(qml.PauliY(1))

Define a cost function based on the above circuit.

>>> def cost(x, generators):
...     X_1, Y_2 = circuit(x, generators=generators)
...     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, generators))
...     x, generators = opt.step(cost, x, generators)

The optimized values for x should now be stored in x together with the optimal gates for the circuit, while steps-vs-cost can be seen by plotting cost_rotosel.

step(objective_fn, x, generators)

Update x with one step of the optimizer.

step(objective_fn, x, generators)[source]

Update x with one step of the optimizer.

  • objective_fn (function) – The objective function for optimization. It must have the signature objective_fn(x, generators=None) with a sequence of the values x and a list of the gates generators as inputs, returning 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.

  • generators (list[Operation]) – List containing the initial pennylane.ops.qubit operators to be used in the circuit and optimized over.


The new variable values \(x^{(t+1)}\) as well as the new generators.

Return type



Using PennyLane