2
$\begingroup$

I am trying to replace the SPSA optimizer in the VQE tutorial of pennylane by the bayesian optimizer of scikit-opimize.

When running the code below I get the error "func should return a scalar".

I think this is not actually the problem since my func, wrapped_cost, returns a scalar which I also print. But I have no idea what the real problem is.

import pennylane as qml
from pennylane import qchem
from pennylane import numpy as np
from skopt import gp_minimize

niter_spsa = 200
true_energy = -1.136189454088
seednum=10
num_params=3
devicename="default.qubit"

#setup hamiltonian
symbols = ["H", "H"]
coordinates = np.array([0.0, 0.0, -0.6614, 0.0, 0.0, 0.6614])
h2_ham, num_qubits = qchem.molecular_hamiltonian(symbols, coordinates)

# Variational ansatz for H_2 
def circuit(params, wires):  #has 3 parameters
    qml.BasisState(np.array([1, 1, 0, 0]), wires=wires)
    for i in wires:
        qml.Rot(*params[i], wires=i)
    qml.CNOT(wires=[2, 3])
    qml.CNOT(wires=[2, 0])
    qml.CNOT(wires=[3, 1])


dev=qml.device(devicename, wires=num_qubits)

def exp_val_circuit(params):
    circuit(params, range(dev.num_wires))
    return qml.expval(h2_ham)

##
cost_spsa = qml.QNode(exp_val_circuit, dev)

def wrapped_cost(params):  # Wrapping the cost function and flattening the parameters to be compatible with noisyopt which assumes a flat array of input parameters
    return cost_spsa(np.asarray(params).reshape(num_qubits, num_params))


##callback for documentation =^intermediate_results in (3)
def callback_fn(xk):
    cost_val = wrapped_cost(xk)

##set initial parameters
np.random.seed(seednum)
init_params = np.random.normal(0, np.pi, (num_qubits, 3), requires_grad=True)
params = list(init_params.copy().reshape(num_qubits * num_params)) #flatten and convert to list (func of gp_minimize takes list as input)

testlist=[i for i in range(12)]
print("Test for wrapped_cost: ",wrapped_cost(testlist), " with tensor list params: ",wrapped_cost(params))

##do optimization
res = gp_minimize(
        wrapped_cost,
        [(2.0,4.0),(-5.0,0.0),(-6.0,-4.0),(0.0,6.0),
        (0.0,2.0),(-3.0,-2.0),(0.0,2.0),(-3.0,0.0),
        (-2.0,2.0),(-4.0,0.0),(0.0,2.0),(1.0,4.0)], #search space chosen on basis of observed parameters in minimizeSPSA for seed 10 
        n_calls=20, #number of calls to the function to be evaluated
        n_initial_points=20, #number of evaluations of the function before approximating it with base_estimator
        random_state=0, #seed
        verbose=True,
        callback=callback_fn
    )
```
$\endgroup$

2 Answers 2

1
$\begingroup$

I was able to reproduce your error. I made several tests on your code and I found that the wrapped_cost function is returning a tensor, not a scalar. However if you try to use something like np.asscalar this causes problems down the line. I don't have a solution to your problem but hopefully this uncovers the root of the problem and you may be able to solve it from here.

$\endgroup$
1
  • $\begingroup$ Thank you. This helped to solve the issue. $\endgroup$ Apr 26, 2022 at 8:00
1
$\begingroup$

np.asscalar as stated by Catalina solves the described problem.

Further problems (e.g. error message cannot convert (1,) array into (3,4) at np.asscalar(cost_spsa(np.asarray(params).reshape(num_qubits, num_params)))) arise, because xk used in the callbackfunction is not just the set of current parameters as for the Spsa but gp_minimize is much more verbose. Thus, also the additional evaluation of the costfunction in the callback is not needed but it is enough to just output xk to get all the needed information.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.