diff --git a/doc/releases/changelog-dev.md b/doc/releases/changelog-dev.md
index 4b450f41684..38f1fdea7a2 100644
--- a/doc/releases/changelog-dev.md
+++ b/doc/releases/changelog-dev.md
@@ -258,6 +258,9 @@
(which is not currently compatible with `KerasLayer`), linking to instructions to enable Keras 2.
[(#5488)](https://github.com/PennyLaneAI/pennylane/pull/5488)
+* Removed the warning that an observable might not be hermitian in `qnode` executions. This enables jit-compilation.
+ [(#5506)](https://github.com/PennyLaneAI/pennylane/pull/5506)
+
Breaking changes 💔
* The private functions `_pauli_mult`, `_binary_matrix` and `_get_pauli_map` from the `pauli` module have been removed. The same functionality can be achieved using newer features in the ``pauli`` module.
diff --git a/pennylane/measurements/counts.py b/pennylane/measurements/counts.py
index 9c291087072..341d4cd2a62 100644
--- a/pennylane/measurements/counts.py
+++ b/pennylane/measurements/counts.py
@@ -14,7 +14,6 @@
"""
This module contains the qml.counts measurement.
"""
-import warnings
from typing import Sequence, Tuple, Optional
import numpy as np
@@ -146,9 +145,6 @@ def circuit():
return CountsMP(obs=op, all_outcomes=all_outcomes)
- if op is not None and not op.is_hermitian: # None type is also allowed for op
- warnings.warn(f"{op.name} might not be hermitian.")
-
if wires is not None:
if op is not None:
raise ValueError(
diff --git a/pennylane/measurements/expval.py b/pennylane/measurements/expval.py
index 41c53040b7b..13994e3153f 100644
--- a/pennylane/measurements/expval.py
+++ b/pennylane/measurements/expval.py
@@ -14,7 +14,6 @@
"""
This module contains the qml.expval measurement.
"""
-import warnings
from typing import Sequence, Tuple, Union
import pennylane as qml
@@ -71,9 +70,6 @@ def circuit(x):
"Expectation values of qml.Identity() without wires are currently not allowed."
)
- if not op.is_hermitian:
- warnings.warn(f"{op.name} might not be hermitian.")
-
return ExpectationMP(obs=op)
diff --git a/pennylane/measurements/sample.py b/pennylane/measurements/sample.py
index c6e68bd90d4..3a014ac1d2c 100644
--- a/pennylane/measurements/sample.py
+++ b/pennylane/measurements/sample.py
@@ -15,7 +15,6 @@
This module contains the qml.sample measurement.
"""
import functools
-import warnings
from typing import Sequence, Tuple, Optional, Union
import numpy as np
@@ -173,9 +172,6 @@ def __init__(self, obs=None, wires=None, eigvals=None, id=None):
super().__init__(obs=obs)
return
- if obs is not None and not obs.is_hermitian: # None type is also allowed for op
- warnings.warn(f"{obs.name} might not be hermitian.")
-
if wires is not None:
if obs is not None:
raise ValueError(
diff --git a/pennylane/measurements/var.py b/pennylane/measurements/var.py
index dadb2444360..fabe6b5ffcb 100644
--- a/pennylane/measurements/var.py
+++ b/pennylane/measurements/var.py
@@ -15,7 +15,6 @@
"""
This module contains the qml.var measurement.
"""
-import warnings
from typing import Sequence, Tuple, Union
import pennylane as qml
@@ -64,9 +63,6 @@ def circuit(x):
"qml.var does not support measuring sequences of measurements or observables"
)
- if not op.is_hermitian:
- warnings.warn(f"{op.name} might not be hermitian.")
-
return VarianceMP(obs=op)
diff --git a/tests/devices/default_qubit/test_default_qubit.py b/tests/devices/default_qubit/test_default_qubit.py
index 8e7ad8c1e94..a4990949bc7 100644
--- a/tests/devices/default_qubit/test_default_qubit.py
+++ b/tests/devices/default_qubit/test_default_qubit.py
@@ -2052,6 +2052,34 @@ def circuit():
assert circuit() == expected
+ @pytest.mark.jax
+ @pytest.mark.parametrize("measurement_func", [qml.expval, qml.var])
+ def test_differentiate_jitted_qnode(self, measurement_func):
+ """Test that a jitted qnode can be correctly differentiated"""
+ import jax
+
+ dev = DefaultQubit()
+
+ def qfunc(x, y):
+ qml.RX(x, 0)
+ return measurement_func(qml.Hamiltonian(y, [qml.Z(0)]))
+
+ qnode = qml.QNode(qfunc, dev, interface="jax")
+ qnode_jit = jax.jit(qml.QNode(qfunc, dev, interface="jax"))
+
+ x = jax.numpy.array(0.5)
+ y = jax.numpy.array([0.5])
+
+ res = qnode(x, y)
+ res_jit = qnode_jit(x, y)
+
+ assert qml.math.allclose(res, res_jit)
+
+ grad = jax.grad(qnode)(x, y)
+ grad_jit = jax.grad(qnode_jit)(x, y)
+
+ assert qml.math.allclose(grad, grad_jit)
+
@pytest.mark.parametrize("max_workers", max_workers_list)
def test_broadcasted_parameter(max_workers):
diff --git a/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py b/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py
index 3efa0f68807..42e9c88e9ec 100644
--- a/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py
+++ b/tests/interfaces/default_qubit_2_integration/test_jax_jit_qnode_default_qubit_2.py
@@ -1520,6 +1520,7 @@ def test_hamiltonian_expansion_analytic(
spy = mocker.spy(qml.transforms, "hamiltonian_expand")
obs = [qml.PauliX(0), qml.PauliX(0) @ qml.PauliZ(1), qml.PauliZ(0) @ qml.PauliZ(1)]
+ @jax.jit
@qnode(
dev,
interface=interface,
diff --git a/tests/measurements/legacy/test_expval_legacy.py b/tests/measurements/legacy/test_expval_legacy.py
index 995551c559f..18cd2835b58 100644
--- a/tests/measurements/legacy/test_expval_legacy.py
+++ b/tests/measurements/legacy/test_expval_legacy.py
@@ -80,24 +80,6 @@ def circuit(x):
custom_measurement_process(new_dev, spy)
- def test_not_an_observable(self, mocker):
- """Test that a warning is raised if the provided
- argument might not be hermitian."""
- dev = qml.device("default.qubit.legacy", wires=2)
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return qml.expval(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- new_dev = circuit.device
- spy = mocker.spy(qml.QubitDevice, "expval")
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
- custom_measurement_process(new_dev, spy)
-
def test_observable_return_type_is_expectation(self, mocker):
"""Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`"""
dev = qml.device("default.qubit.legacy", wires=2)
diff --git a/tests/measurements/legacy/test_measurements_legacy.py b/tests/measurements/legacy/test_measurements_legacy.py
index d524095f7a3..f7f749385e2 100644
--- a/tests/measurements/legacy/test_measurements_legacy.py
+++ b/tests/measurements/legacy/test_measurements_legacy.py
@@ -24,8 +24,6 @@
Shots,
StateMeasurement,
StateMP,
- expval,
- var,
)
from pennylane.wires import Wires
@@ -66,22 +64,6 @@ def test_shape_unrecognized_error():
mp.shape(dev, Shots(None))
-@pytest.mark.parametrize("stat_func", [expval, var])
-def test_not_an_observable(stat_func):
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
-
- dev = qml.device("default.qubit.legacy", wires=2)
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return stat_func(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
-
class TestSampleMeasurement:
"""Tests for the SampleMeasurement class."""
diff --git a/tests/measurements/legacy/test_sample_legacy.py b/tests/measurements/legacy/test_sample_legacy.py
index 495fdbaa937..6679d610a03 100644
--- a/tests/measurements/legacy/test_sample_legacy.py
+++ b/tests/measurements/legacy/test_sample_legacy.py
@@ -251,22 +251,6 @@ def circuit():
custom_measurement_process(dev, spy)
- def test_not_an_observable(self, mocker):
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
- dev = qml.device("default.qubit.legacy", wires=2, shots=10)
- spy = mocker.spy(qml.QubitDevice, "sample")
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return qml.sample(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
- custom_measurement_process(dev, spy)
-
def test_observable_return_type_is_sample(self, mocker):
"""Test that the return type of the observable is :attr:`ObservableReturnTypes.Sample`"""
n_shots = 10
diff --git a/tests/measurements/legacy/test_var_legacy.py b/tests/measurements/legacy/test_var_legacy.py
index ef84166ba15..3c6f912a991 100644
--- a/tests/measurements/legacy/test_var_legacy.py
+++ b/tests/measurements/legacy/test_var_legacy.py
@@ -77,22 +77,6 @@ def circuit(x):
custom_measurement_process(dev, spy)
- def test_not_an_observable(self, mocker):
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
- dev = qml.device("default.qubit.legacy", wires=2)
- spy = mocker.spy(qml.QubitDevice, "var")
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return qml.var(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
- custom_measurement_process(dev, spy)
-
def test_observable_return_type_is_variance(self, mocker):
"""Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`"""
dev = qml.device("default.qubit.legacy", wires=2)
diff --git a/tests/measurements/test_counts.py b/tests/measurements/test_counts.py
index dddd7749a8c..550c65e0552 100644
--- a/tests/measurements/test_counts.py
+++ b/tests/measurements/test_counts.py
@@ -61,13 +61,6 @@ def test_providing_observable_and_wires(self):
):
qml.counts(qml.PauliZ(0), wires=[0, 1])
- def test_observable_might_not_be_hermitian(self):
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- qml.counts(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
def test_hash(self):
"""Test that the hash property includes the all_outcomes property."""
m1 = qml.counts(all_outcomes=True)
diff --git a/tests/measurements/test_expval.py b/tests/measurements/test_expval.py
index b357690dd92..bc73b5ba83e 100644
--- a/tests/measurements/test_expval.py
+++ b/tests/measurements/test_expval.py
@@ -73,19 +73,6 @@ def circuit(x):
else:
assert res.dtype == r_dtype
- def test_not_an_observable(self):
- """Test that a warning is raised if the provided
- argument might not be hermitian."""
- dev = qml.device("default.qubit", wires=2)
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return qml.expval(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
def test_observable_return_type_is_expectation(self):
"""Test that the return type of the observable is :attr:`ObservableReturnTypes.Expectation`"""
dev = qml.device("default.qubit", wires=2)
diff --git a/tests/measurements/test_measurements.py b/tests/measurements/test_measurements.py
index 37ae0423378..0b592b2a524 100644
--- a/tests/measurements/test_measurements.py
+++ b/tests/measurements/test_measurements.py
@@ -293,22 +293,6 @@ def test_queueing_tensor_observable(self, op1, op2, stat_func, return_type):
assert isinstance(meas_proc, MeasurementProcess)
assert meas_proc.return_type == return_type
- def test_not_an_observable(self, stat_func, return_type): # pylint: disable=unused-argument
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
- if stat_func is sample:
- pytest.skip("Sampling is not yet supported with symbolic operators.")
-
- dev = qml.device("default.qubit", wires=2)
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return stat_func(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
class TestProperties:
"""Test for the properties"""
diff --git a/tests/measurements/test_sample.py b/tests/measurements/test_sample.py
index 8b9976e5e18..b0a4e961daa 100644
--- a/tests/measurements/test_sample.py
+++ b/tests/measurements/test_sample.py
@@ -126,19 +126,6 @@ def circuit():
assert result[2].dtype == np.dtype("int")
assert np.array_equal(result[2].shape, (n_sample,))
- def test_not_an_observable(self):
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
- dev = qml.device("default.qubit", wires=2, shots=10)
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return qml.sample(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
def test_observable_return_type_is_sample(self):
"""Test that the return type of the observable is :attr:`ObservableReturnTypes.Sample`"""
n_shots = 10
diff --git a/tests/measurements/test_var.py b/tests/measurements/test_var.py
index da1079c2dfd..763b88206b2 100644
--- a/tests/measurements/test_var.py
+++ b/tests/measurements/test_var.py
@@ -49,19 +49,6 @@ def circuit(x):
else:
assert res.dtype == r_dtype
- def test_not_an_observable(self):
- """Test that a UserWarning is raised if the provided
- argument might not be hermitian."""
- dev = qml.device("default.qubit", wires=2)
-
- @qml.qnode(dev)
- def circuit():
- qml.RX(0.52, wires=0)
- return qml.var(qml.prod(qml.PauliX(0), qml.PauliZ(0)))
-
- with pytest.warns(UserWarning, match="Prod might not be hermitian."):
- _ = circuit()
-
def test_observable_return_type_is_variance(self):
"""Test that the return type of the observable is :attr:`ObservableReturnTypes.Variance`"""
dev = qml.device("default.qubit", wires=2)
diff --git a/tests/ops/op_math/test_prod.py b/tests/ops/op_math/test_prod.py
index 08b2be3a907..d1d9b861f01 100644
--- a/tests/ops/op_math/test_prod.py
+++ b/tests/ops/op_math/test_prod.py
@@ -1485,8 +1485,8 @@ def circuit(weights):
true_grad = -qnp.sqrt(2) * qnp.cos(weights[0] / 2) * qnp.sin(weights[0] / 2)
assert qnp.allclose(grad, true_grad)
- def test_non_hermitian_obs_not_supported(self):
- """Test that non-hermitian ops in a measurement process will raise a warning."""
+ def test_non_supported_obs_not_supported(self):
+ """Test that non-supported ops in a measurement process will raise an error."""
wires = [0, 1]
dev = qml.device("default.qubit", wires=wires)
prod_op = Prod(qml.RX(1.23, wires=0), qml.Identity(wires=1))
diff --git a/tests/ops/op_math/test_sprod.py b/tests/ops/op_math/test_sprod.py
index c77a6c7e7b7..f76fce85c74 100644
--- a/tests/ops/op_math/test_sprod.py
+++ b/tests/ops/op_math/test_sprod.py
@@ -1084,20 +1084,6 @@ def circuit(weights):
true_grad = 100 * -qnp.sqrt(2) * qnp.cos(weights[0] / 2) * qnp.sin(weights[0] / 2)
assert qnp.allclose(grad, true_grad)
- def test_non_hermitian_obs_not_supported(self):
- """Test that non-hermitian ops in a measurement process will raise a warning."""
- wires = [0, 1]
- dev = qml.device("default.qubit", wires=wires)
- sprod_op = SProd(1.0 + 2.0j, qml.RX(1.23, wires=0))
-
- @qml.qnode(dev)
- def my_circ():
- qml.PauliX(0)
- return qml.expval(sprod_op)
-
- with pytest.raises(NotImplementedError):
- my_circ()
-
@pytest.mark.torch
@pytest.mark.parametrize("diff_method", ("parameter-shift", "backprop"))
def test_torch(self, diff_method):
diff --git a/tests/ops/op_math/test_sum.py b/tests/ops/op_math/test_sum.py
index 32c149f412e..69e5e723c02 100644
--- a/tests/ops/op_math/test_sum.py
+++ b/tests/ops/op_math/test_sum.py
@@ -1267,20 +1267,6 @@ def circuit(weights):
true_grad = qnp.array([-0.09347337, -0.18884787, -0.28818254])
assert qnp.allclose(grad, true_grad)
- def test_non_hermitian_op_in_measurement_process(self):
- """Test that non-hermitian ops in a measurement process will raise a warning."""
- wires = [0, 1]
- dev = qml.device("default.qubit", wires=wires)
- sum_op = Sum(Prod(qml.RX(1.23, wires=0), qml.Identity(wires=1)), qml.Identity(wires=1))
-
- @qml.qnode(dev, interface=None)
- def my_circ():
- qml.PauliX(0)
- return qml.expval(sum_op)
-
- with pytest.warns(UserWarning, match="Sum might not be hermitian."):
- my_circ()
-
def test_params_can_be_considered_trainable(self):
"""Tests that the parameters of a Sum are considered trainable."""
dev = qml.device("default.qubit", wires=2)