Quantum Natural Gradient is Bugged with kUpCCGSD

Hi,
I am using pennylane’s Quantum Natural Gradient optimizer to run VQE on H2 with the kUpGCCSD Ansatz. I get the following error when I try to run my code:

ValueError: solve1: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (m,m),(m)->(m) (size 1 is different from 6)

My k is set to 1 for the kUpCCGSD circuit. The same issue occurs when k is set to 2. What is curious is that the code works completely fine for the GateFabric ansatz.

My code is here:

#Get H2 Hamiltonian
geo_file = "h2.xyz"

symbols, coordinates = qml.qchem.read_structure(geo_file)
hamiltonian, qubits = qml.qchem.molecular_hamiltonian(symbols, coordinates)

#Get device
dev = qml.device("default.qubit", wires=qubits, shots = 1000)
hf_state = np.array([1, 1, 0, 0], requires_grad=True)

#Define Circuit
def kUpCCGSD(init_state, singles, doubles, k, delta_sz = 0):
    def circuit(params, wires):
        qml.kUpCCGSD(weights = params, wires = wires, k = k,
                    delta_sz = delta_sz, init_state = init_state)
    return circuit, qml.kUpCCGSD.shape(k=k,
                    n_wires=len(init_state), delta_sz=delta_sz)


#Get Circuit
singles, doubles = qml.qchem.excitations(2, 4)

ansatz_circuit, num_params = kUpCCGSD(init_state = hf_state, singles = singles, doubles = doubles, k = 1)
print(num_params)
parameters = np.random.uniform(low=0, high=2 * np.pi, size=num_params, requires_grad=True)
print(parameters)

@qml.qnode(dev)
def cost3(params):
#     params = params.reshape(num_params)
    ansatz_circuit(params, wires = [0, 1, 2, 3])
    return qml.expval(hamiltonian)

hamiltonian = qml.Hamiltonian(np.array(hamiltonian.coeffs, requires_grad=False), hamiltonian.ops, grouping_type='qwc')

opt = qml.QNGOptimizer(0.1, lam=0.001, approx="block-diag")
# opt = qml.GradientDescentOptimizer()
prev_energy = cost3(parameters)
print(prev_energy)
qngd_cost = []

#Loop with a tracker, to recover the total shots used
with qml.Tracker(cost.device) as tracker:
    for n in range(max_iterations):
        print(parameters) #Print line debugging... the parameter array is always the correct size, but for some reason the code is thinking it is size 1.

        ###The Error occurs below this
        parameters, prev_energy = opt.step_and_cost(cost3, parameters)
        ###The error occurs above this

        qngd_cost.append(prev_energy)
        energy = cost3(parameters)
        conv = np.abs(energy - prev_energy)

        if n % 4 == 0:
            print(
            "Iteration = {:},  Energy = {:.8f} Ha".format(n, energy)
            )

        if conv <= conv_tol:
            break


print("\nFinal convergence parameter = {:.8f} Ha".format(conv))
print("Number of iterations = ", n)
print("Final value of the ground-state energy = {:.8f} Ha".format(energy))
print(
    "Accuracy with respect to the FCI energy: {:.8f} Ha ({:.8f} kcal/mol)".format(
        np.abs(energy - exact_value), np.abs(energy - exact_value) * 627.503
    )
)
print()
print("Final circuit parameters = \n", params)
print(tracker.totals)

More Error details:

ValueError                                Traceback (most recent call last)
Input In [146], in <cell line: 9>()
     10 for n in range(max_iterations):
     11     print(parameters)
---> 12     parameters, prev_energy = opt.step_and_cost(cost3, parameters)
     13     qngd_cost.append(prev_energy)
     14     energy = cost3(parameters)

File ~/opt/anaconda3/lib/python3.9/site-packages/pennylane/optimize/qng.py:219, in QNGOptimizer.step_and_cost(self, qnode, grad_fn, recompute_tensor, metric_tensor_fn, *args, **kwargs)
    214     self.metric_tensor = self.metric_tensor + self.lam * qml.math.eye(
    215         size, like=_metric_tensor
    216     )
    218 g, forward = self.compute_grad(qnode, args, kwargs, grad_fn=grad_fn)
--> 219 new_args = np.array(self.apply_grad(g, args), requires_grad=True)
    221 if forward is None:
    222     forward = qnode(*args, **kwargs)

File ~/opt/anaconda3/lib/python3.9/site-packages/pennylane/optimize/qng.py:293, in QNGOptimizer.apply_grad(self, grad, args)
    291 grad_flat = np.array(list(_flatten(grad)))
    292 x_flat = np.array(list(_flatten(args)))
--> 293 x_new_flat = x_flat - self.stepsize * np.linalg.solve(self.metric_tensor, grad_flat)
    294 return unflatten(x_new_flat, args)

File ~/opt/anaconda3/lib/python3.9/site-packages/pennylane/numpy/wrapper.py:117, in tensor_wrapper.<locals>._wrapped(*args, **kwargs)
    114         tensor_kwargs["requires_grad"] = _np.any([i.requires_grad for i in tensor_args])
    116 # evaluate the original object
--> 117 res = obj(*args, **kwargs)
    119 if isinstance(res, _np.ndarray):
    120     # only if the output of the object is a ndarray,
    121     # then convert to a PennyLane tensor
    122     res = tensor(res, **tensor_kwargs)

File ~/opt/anaconda3/lib/python3.9/site-packages/autograd/tracer.py:48, in primitive.<locals>.f_wrapped(*args, **kwargs)
     46     return new_box(ans, trace, node)
     47 else:
---> 48     return f_raw(*args, **kwargs)

File <__array_function__ internals>:180, in solve(*args, **kwargs)

File ~/opt/anaconda3/lib/python3.9/site-packages/numpy/linalg/linalg.py:400, in solve(a, b)
    398 signature = 'DD->D' if isComplexType(t) else 'dd->d'
    399 extobj = get_linalg_error_extobj(_raise_linalgerror_singular)
--> 400 r = gufunc(a, b, signature=signature, extobj=extobj)
    402 return wrap(r.astype(result_t, copy=False))

ValueError: solve1: Input operand 1 has a mismatch in its core dimension 0, with gufunc signature (m,m),(m)->(m) (size 1 is different from 6)

Hey @trifire! Thank you for finding this! Indeed, there is a bug! I’ve made an issue for it already: https://github.com/PennyLaneAI/pennylane/issues/2910

It has to do with a ill-defined gradient method for using the parameter-shift rule with qml.kUpCCGSD. Will be fixed soon!