Repository: PennyLaneAI/pennylane
Pull request #5076 (2024-01-17 14:50:57)

update more spots that use MP.name
Same as #5071 but in other places.

I'm a little worried that maybe we shouldn't deprecate `MeasurementProcess.name` at all... seems like we kinda depend on it? My first thought was to just make them more correct (eg. "State", "Probs"), but I don't think any devices have those saved in their `dev.observables` so I suppose this might still be the best way forward

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5076?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) Report
Attention: `2 lines` in your changes are missing coverage. Please review.
> Comparison is base [(`c01cb4b`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/commit/c01cb4b96f758a9f1a0c4e422115829b80e113cb?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.67% compared to head [(`c1e0434`)](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5076?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) 99.66%.
> Report is 21 commits behind head on master.

| [Files](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5076?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) | Patch % | Lines |
|---|---|---|
| [pennylane/workflow/jacobian\_products.py](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5076?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI#diff-cGVubnlsYW5lL3dvcmtmbG93L2phY29iaWFuX3Byb2R1Y3RzLnB5) | 91.30% | [2 Missing :warning: ](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5076?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI) |

<details><summary>Additional details and impacted files</summary>


```diff
@@            Coverage Diff             @@
##           master    #5076      +/-   ##
==========================================
- Coverage   99.67%   99.66%   -0.02%     
==========================================
  Files         394      394              
  Lines       35670    35467     -203     
==========================================
- Hits        35554    35347     -207     
- Misses        116      120       +4     
```



</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/PennyLaneAI/pennylane/pull/5076?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).   
:loudspeaker: Have feedback on the report? [Share it here](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=PennyLaneAI).

josh146: @timmysilv I could provide some context if needed since (I think??) I originally added this. The original motivation was mostly `repr`/printing for end users (so that circuits would show as `qml.expval(qml.PauliZ)` when displayed etc.)
timmysilv: @josh146 we're deprecating `MeasurementProcess.name` and `MeasurementProcess.data`, because they were _always_ "Identity" and `[]`, respectively (see [file at time of adding](https://github.com/PennyLaneAI/pennylane/blob/b32b702e3922345cd524854782e932e64f5aa939/pennylane/measurements/measurements.py#L155-L166)). Every time we checked `MP.name`, it was "Identity", even today:
```pycon
>>> qml.state().name
/Users/matthews/src/github.com/PennyLaneAI/pennylane/pennylane/measurements/measurements.py:196: PennyLaneDeprecationWarning: MeasurementProcess.name is deprecated, and will be removed in an upcoming release. To get the name of an observable from a measurement, use MeasurementProcess.obs.name instead
  warn(
'Identity'
```

that said, `Device` clearly does check it and handle it, even though it was always "Identity". While I hoped this wouldn't affect things, it still can sometimes as we're seeing.
josh146: got it, thanks @timmysilv!

Patch:
diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index eefb0d08d..82bfc5ed8 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -90,6 +90,7 @@
   values that are no longer needed.
   [(#5047)](https://github.com/PennyLaneAI/pennylane/pull/5047)
   [(#5071)](https://github.com/PennyLaneAI/pennylane/pull/5071)
+  [(#5076)](https://github.com/PennyLaneAI/pennylane/pull/5076)
 
 * Calling `qml.matrix` without providing a `wire_order` on objects where the wire order could be
   ambiguous now raises a warning. In the future, the `wire_order` argument will be required in
diff --git a/pennylane/_device.py b/pennylane/_device.py
index 5aabc9a1c..aaab968cf 100644
--- a/pennylane/_device.py
+++ b/pennylane/_device.py
@@ -608,7 +608,8 @@ class Device(abc.ABC):
         function accepts a queuable object (including a PennyLane operation
         and observable) and returns ``True`` if supported by the device."""
         return qml.BooleanFn(
-            lambda obj: not isinstance(obj, QuantumScript) and self.supports_operation(obj.name)
+            lambda obj: not isinstance(obj, QuantumScript)
+            and (isinstance(obj, MeasurementProcess) or self.supports_operation(obj.name))
         )
 
     def custom_expand(self, fn):
@@ -986,8 +987,10 @@ class Device(abc.ABC):
                 )
 
         for o in observables:
-            if isinstance(o, qml.measurements.MeasurementProcess) and o.obs is not None:
+            if isinstance(o, MeasurementProcess):
                 o = o.obs
+                if o is None:
+                    continue
 
             if isinstance(o, Tensor):
                 # TODO: update when all capabilities keys changed to "supports_tensor_observables"


Test patch:
diff --git a/tests/test_device.py b/tests/test_device.py
index 1cd774725..fead0e735 100644
--- a/tests/test_device.py
+++ b/tests/test_device.py
@@ -60,6 +60,21 @@ def mock_device_with_observables(monkeypatch):
         yield get_device
 
 
+@pytest.fixture(scope="function")
+def mock_device_with_identity(monkeypatch):
+    """A function to create a mock device with non-empty observables"""
+    with monkeypatch.context() as m:
+        m.setattr(Device, "__abstractmethods__", frozenset())
+        m.setattr(Device, "operations", mock_device_paulis + ["Identity"])
+        m.setattr(Device, "observables", mock_device_paulis + ["Identity"])
+        m.setattr(Device, "short_name", "MockDevice")
+
+        def get_device(wires=1):
+            return Device(wires=wires)
+
+        yield get_device
+
+
 @pytest.fixture(scope="function")
 def mock_device_supporting_paulis(monkeypatch):
     """A function to create a mock device with non-empty observables"""
@@ -406,6 +421,15 @@ class TestInternalFunctions:  # pylint:disable=too-many-public-methods
         with pytest.raises(ValueError, match="Postselection is not supported"):
             dev.check_validity(queue, observables)
 
+    def test_check_validity_on_non_observable_measurement(self, mock_device_with_identity, recwarn):
+        """Test that using non-observable measurements like state() works."""
+        dev = mock_device_with_identity(wires=1)
+        queue = []
+        observables = [qml.state()]
+
+        dev.check_validity(queue, observables)
+        assert len(recwarn) == 0
+
     def test_args(self, mock_device):
         """Test that the device requires correct arguments"""
         with pytest.raises(
@@ -622,6 +646,12 @@ class TestInternalFunctions:  # pylint:disable=too-many-public-methods
         assert qml.equal(expanded_tape, expected_tape)
         assert len(recwarn) == 0
 
+    def test_stopping_condition_passes_with_non_obs_mp(self, mock_device_with_identity, recwarn):
+        """Test that Device.stopping_condition passes with non-observable measurements"""
+        dev = mock_device_with_identity(wires=1)
+        assert dev.stopping_condition(qml.state())
+        assert len(recwarn) == 0
+
 
 # pylint: disable=too-few-public-methods
 class TestClassmethods: