Repository: PennyLaneAI/pennylane
Pull request #3752 (2023-02-10 19:26:45)

Add check for auto interface and device that do not support backprop
**Description of the Change:**

With the "auto" interface raises an error at initialization of QNode if the device does not support backprop.

It allows checks for all diff_method expect `best` and `backprop` as they require the interface.

github-actions[bot]: Hello. You may have forgotten to update the changelog!
Please edit [`doc/releases/changelog-dev.md`](/PennyLaneAI/pennylane/blob/master/doc/releases/changelog-dev.md) with:
* A one-to-two sentence description of the change. You may include a small working example for new features.
* A link back to this PR.
* Your name (or GitHub username) in the contributors section.
codecov[bot]: # [Codecov](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3752?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
> Merging [#3752](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3752?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (4af65c8) into [master](https://codecov.io/gh/PennyLaneAI/pennylane/commit/08511eaa8ae13953d2e5464217864bf2ab028333?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) (08511ea) will **decrease** coverage by `0.01%`.
> The diff coverage is `75.00%`.

```diff
@@            Coverage Diff             @@
##           master    #3752      +/-   ##
==========================================
- Coverage   99.82%   99.82%   -0.01%     
==========================================
  Files         330      330              
  Lines       28909    28913       +4     
==========================================
+ Hits        28858    28861       +3     
- Misses         51       52       +1     
```


| [Impacted Files](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3752?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Coverage Δ | |
|---|---|---|
| [pennylane/qnode.py](https://codecov.io/gh/PennyLaneAI/pennylane/pull/3752?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3Fub2RlLnB5) | `99.60% <75.00%> (-0.40%)` | :arrow_down: |

Help us with your feedback. Take ten seconds to tell us [how you rate us](https://about.codecov.io/nps?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI). Have a feature suggestion? [Share it here.](https://app.codecov.io/gh/feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI)


Patch:
diff --git a/pennylane/qnode.py b/pennylane/qnode.py
index 5902f0cc7..620983dd8 100644
--- a/pennylane/qnode.py
+++ b/pennylane/qnode.py
@@ -460,7 +460,15 @@ class QNode:
             self.gradient_fn = None
             self.gradient_kwargs = {}
             return
-        if self.interface == "auto":
+        if self.interface == "auto" and self.diff_method in ["backprop", "best"]:
+            if self.diff_method == "backprop":
+                # Check that the device has the capabilities to support backprop
+                backprop_devices = self.device.capabilities().get("passthru_devices", None)
+                if backprop_devices is None:
+                    raise qml.QuantumFunctionError(
+                        f"The {self.device.short_name} device does not support native computations with "
+                        "autodifferentiation frameworks."
+                    )
             return
 
         self.gradient_fn, self.gradient_kwargs, self.device = self.get_gradient_fn(


Test patch:
diff --git a/tests/devices/test_lightning_qubit.py b/tests/devices/test_lightning_qubit.py
index b62060910..d89e2eee0 100644
--- a/tests/devices/test_lightning_qubit.py
+++ b/tests/devices/test_lightning_qubit.py
@@ -42,6 +42,41 @@ def test_integration():
     assert np.allclose(qml.grad(qn_l)(weights), qml.grad(qn_d)(weights))
 
 
+def test_no_backprop_auto_interface():
+    """Test that lightning.qubit does not support the backprop
+    differentiation method."""
+
+    dev = qml.device("lightning.qubit", wires=2)
+
+    def circuit():
+        """Simple quantum function."""
+        return qml.expval(qml.PauliZ(0))
+
+    with pytest.raises(
+        qml.QuantumFunctionError,
+        match="The lightning.qubit device does not support native "
+        "computations with autodifferentiation frameworks.",
+    ):
+        qml.QNode(circuit, dev, diff_method="backprop")
+
+
+def test_finite_shots_adjoint():
+    """Test that shots and adjoint diff raises an error."""
+
+    dev = qml.device("lightning.qubit", wires=2, shots=2)
+
+    def circuit():
+        """Simple quantum function."""
+        return qml.expval(qml.PauliZ(0))
+
+    with pytest.warns(
+        UserWarning,
+        match="Requested adjoint differentiation to be computed with finite shots. Adjoint differentiation always "
+        "calculated exactly.",
+    ):
+        qml.QNode(circuit, dev, diff_method="adjoint")
+
+
 class TestDtypePreserved:
     """Test that the user-defined dtype of the device is preserved for QNode
     evaluation"""
diff --git a/tests/test_qnode.py b/tests/test_qnode.py
index 833230d4f..a4451e1f5 100644
--- a/tests/test_qnode.py
+++ b/tests/test_qnode.py
@@ -361,16 +361,15 @@ class TestValidation:
 
         qn = QNode(dummyfunc, dev, diff_method="device")
         assert qn.diff_method == "device"
-        assert qn.gradient_fn is None
+        assert qn.gradient_fn == "device"
 
         qn = QNode(dummyfunc, dev, interface="autograd", diff_method="device")
         assert qn.diff_method == "device"
         assert qn.gradient_fn == "device"
-        mock_device.assert_called_once()
 
         qn = QNode(dummyfunc, dev, diff_method="finite-diff")
         assert qn.diff_method == "finite-diff"
-        assert qn.gradient_fn is None
+        assert qn.gradient_fn is qml.gradients.finite_diff
 
         qn = QNode(dummyfunc, dev, interface="autograd", diff_method="finite-diff")
         assert qn.diff_method == "finite-diff"
@@ -378,7 +377,7 @@ class TestValidation:
 
         qn = QNode(dummyfunc, dev, diff_method="spsa")
         assert qn.diff_method == "spsa"
-        assert qn.gradient_fn is None
+        assert qn.gradient_fn is qml.gradients.spsa_grad
 
         qn = QNode(dummyfunc, dev, interface="autograd", diff_method="spsa")
         assert qn.diff_method == "spsa"
@@ -386,7 +385,7 @@ class TestValidation:
 
         qn = QNode(dummyfunc, dev, diff_method="parameter-shift")
         assert qn.diff_method == "parameter-shift"
-        assert qn.gradient_fn is None
+        assert qn.gradient_fn is qml.gradients.param_shift
 
         qn = QNode(dummyfunc, dev, interface="autograd", diff_method="parameter-shift")
         assert qn.diff_method == "parameter-shift"