Hello!
I would like to use the ShotAdaptiveOptimiser for depth 1 QAOA. However, I get an error if the depth of the QAOA circuit is not greater or equal to 2. Below, I have reproduced the same error using the example code from the ShotAdaptiveOptimiser documentation page, by only modifying the number of StronglyEntanglingLayers to 1.
import pennylane as qml
from pennylane import numpy as npp
print(qml.about())
coeffs = [2, 4, -1, 5, 2]
obs = [
qml.PauliX(1),
qml.PauliZ(1),
qml.PauliX(0) @ qml.PauliX(1),
qml.PauliY(0) @ qml.PauliY(1),
qml.PauliZ(0) @ qml.PauliZ(1)
]
H = qml.Hamiltonian(coeffs, obs)
dev = qml.device("default.qubit", wires=2, shots=100)
cost = qml.ExpvalCost(qml.templates.StronglyEntanglingLayers, H, dev)
shape = qml.templates.StronglyEntanglingLayers.shape(n_layers=1, n_wires=2)
params = npp.random.random(shape)
print(params)
opt = qml.ShotAdaptiveOptimizer(min_shots=10)
for i in range(6):
params = opt.step(cost, params)
print(f"Step {i}: cost = {cost(params):.2f}, shots_used = {opt.total_shots_used}")
Here is the output of running the code above:
[[[0.34656026 0.20603406 0.97567429]
[0.89482299 0.70363518 0.84379755]]]
Step 0: cost = 1.14, shots_used = 120
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
c:\Code\Shot_Adaptive_Opt_Tests.ipynb Cell 2 in 1
17 opt = qml.ShotAdaptiveOptimizer(min_shots=10)
18 for i in range(6):
---> 19 params = opt.step(cost, params)
20 print(f"Step {i}: cost = {cost(params):.2f}, shots_used = {opt.total_shots_used}")
File c:\ProgramData\Anaconda3\lib\site-packages\pennylane\optimize\shot_adaptive.py:448, in ShotAdaptiveOptimizer.step(self, objective_fn, *args, **kwargs)
444 self.total_shots_used += self.shots_used
446 # compute the gradient, as well as the variance in the gradient,
447 # using the number of shots determined by the array s.
--> 448 grads, grad_variances = self.compute_grad(objective_fn, args, kwargs)
449 new_args = self.apply_grad(grads, args)
451 if self.xi is None:
File c:\ProgramData\Anaconda3\lib\site-packages\pennylane\optimize\shot_adaptive.py:404, in ShotAdaptiveOptimizer.compute_grad(self, objective_fn, args, kwargs)
401 s = np.zeros_like(grad[0])
403 for idx in p_ind:
--> 404 grad_slice = grad[(slice(0, self.s[i][idx]),) + idx]
405 g[idx] = np.mean(grad_slice)
406 s[idx] = np.var(grad_slice, ddof=1)
File c:\ProgramData\Anaconda3\lib\site-packages\pennylane\numpy\tensor.py:187, in tensor.__getitem__(self, *args, **kwargs)
186 def __getitem__(self, *args, **kwargs):
--> 187 item = super().__getitem__(*args, **kwargs)
189 if not isinstance(item, tensor):
190 item = tensor(item, requires_grad=self.requires_grad)
IndexError: too many indices for array: array is 2-dimensional, but 3 were indexed
The output of running qml.about()
is the following:
Name: PennyLane
Version: 0.30.0
Summary: PennyLane is a Python quantum machine learning library by Xanadu Inc.
Home-page: https://github.com/XanaduAI/pennylane
Author:
Author-email:
License: Apache License 2.0
Location: c:\programdata\anaconda3\lib\site-packages
Requires: appdirs, autograd, autoray, cachetools, networkx, numpy, pennylane-lightning, requests, rustworkx, scipy, semantic-version, toml
Required-by: PennyLane-Lightning
Platform info: Windows-10-10.0.19045-SP0
Python version: 3.9.15
Numpy version: 1.23.5
Scipy version: 1.10.1
Installed devices:
- lightning.qubit (PennyLane-Lightning-0.30.0)
- default.gaussian (PennyLane-0.30.0)
- default.mixed (PennyLane-0.30.0)
- default.qubit (PennyLane-0.30.0)
- default.qubit.autograd (PennyLane-0.30.0)
- default.qubit.jax (PennyLane-0.30.0)
- default.qubit.tf (PennyLane-0.30.0)
- default.qubit.torch (PennyLane-0.30.0)
- default.qutrit (PennyLane-0.30.0)
- null.qubit (PennyLane-0.30.0)
None
I have tried modifying the ShotAdaptiveOptimiser class code in the pennylane package to get more information about the error root, and I could find out that the first time the class method compute_grad
is executed, the class attribute self.s
has the same shape as the params
variable defined and printed in the code above, that is
[tensor([[[10, 10, 10],
[10, 10, 10]]], dtype=int64, requires_grad=True)]
However, after the first iteration, the class attribute self.s
has lost one axis, and looks like this
[tensor([[5, 5, 5],
[5, 5, 5]], dtype=int64, requires_grad=True)]
Moreover, I also believe that the code in line 482 in shot_adaptive.py
which is
self.s[idx] = np.squeeze(np.int64(np.clip(s, min(2, self.min_shots), smax)))
should be
self.s[idx] = np.squeeze(np.int64(np.clip(s, max(2, self.min_shots), smax)))
so that the number of shots to use is always greater or equal to self.min_shots
, which might be greater than 2. There must also be another error somewhere, because as you can see in the value of self.s
after the first iteration, the number of shots to use is strictly less than 10, which was the minimum defined when the qml.ShotAdaptiveOptimizer
object was created.
Thank you very much in advance.