PennyLaneAI / pennylane

PennyLane is a cross-platform Python library for quantum computing, quantum machine learning, and quantum chemistry. Train a quantum computer the same way as a neural network.
https://pennylane.ai
Apache License 2.0
2.18k stars 569 forks source link

[BUG] Split non commuting fails with autograd `requires_grad=False` coefficients #5924

Open josh146 opened 3 days ago

josh146 commented 3 days ago

The following code, which uses the append_gate transformation present within qml.optimize.AdaptiveOptimizer, works fine with default.qubit:

import pennylane as qml
from pennylane.optimize.adaptive import append_gate
from pennylane import numpy as np

H, qubits = qml.qchem.molecular_hamiltonian(
    ["Li", "H"],
    np.array([0.0, 0.0, 0.0, 0.0, 0.0, 2.969280527]),
    active_electrons=active_electrons,
    active_orbitals=5
)

operator_pool = [qml.CRX(0.0, [0, 1]), qml.CRY(0.0, [1, 2])]

dev = qml.device("qulacs.simulator", wires=10)

@qml.qnode(dev, diff_method="parameter-shift")
def circuit():
    for i in range(3):
        qml.RX(0.5, i)

    return qml.expval(H)
>>> params = np.array([0.1, 0.2], requires_grad=True)
>> qml.grad(lambda p: append_gate(circuit, p, operator_pool)())(params)
array([-0.00393102, -0.00063065])

However, change the device to qulacs.simulator (which uses the old device API), and an error is raised:

>>> qml.grad(lambda p: append_gate(circuit, p, operator_pool)())(params)
NonDifferentiableError: -6.917117171256823 is non-differentiable. Set the requires_grad attribute to True.

This means that qml.AdapativeOptimizer cannot be used with devices like qulacs.simulator.

Note that this error appears to be peculiar to the following situation:

If the Hamiltonian is generated manually, the above code works correctly on both devices.

albi3ro commented 2 days ago

Note that the issue is not particularily with the qulacs device, but with split_non_commuting.

Sticking qml.transforms.split_non_commuting onto the qnode causes the same error.

from pennylane.optimize.adaptive import append_gate
from pennylane import numpy as np

H, qubits = qml.qchem.molecular_hamiltonian(
    ["Li", "H"],
    np.array([0.0, 0.0, 0.0, 0.0, 0.0, 2.969280527]),
    active_electrons=2,
    active_orbitals=5
)

operator_pool = [qml.CRX(0.0, [0, 1]), qml.CRY(0.0, [1, 2])]

dev = qml.device("default.qubit", wires=10)

@qml.transforms.split_non_commuting
@qml.qnode(dev, diff_method="parameter-shift")
def circuit():
    for i in range(3):
        qml.RX(0.5, i)

    return qml.expval(H)

params = np.array([0.1, 0.2], requires_grad=True)
qml.grad(lambda p: append_gate(circuit, p, operator_pool)())(params)
albi3ro commented 2 days ago

This may also be related to #5824

josh146 commented 2 days ago

Thanks @albi3ro! I suspected it was something to do with the Hamiltonian, but didn't realize it was because H had non-commuting terms.

Is the bug present with just split_non_commuting and non-H-commuting-supporting-devices + grad? In which case, we could remove the append_gate transform from the minimal error example

albi3ro commented 2 days ago

It has less to do with the qulacs simulator, and more about a device that doesn't natively support hamiltonians.

Why append_gate causes this, i have no idea.

josh146 commented 2 days ago

oops, typo in my message, have updated it!

albi3ro commented 2 days ago

Never mind. This has nothing to do with append_gate.

The issue can also be replicated with:

H = pnp.array(0.5, requires_grad=False) * qml.Y(0)

dev = qml.device("default.qubit", wires=10)

@qml.transforms.split_non_commuting
@qml.qnode(dev, diff_method="adjoint")
def circuit(x):
    qml.RX(x, 0)
    return qml.expval(H)
params = pnp.array(0.1, requires_grad=True)
qml.grad(circuit)(params)
josh146 commented 2 days ago

Thanks, that's great! Much more minimal now