Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] Add is_hermitian property to Operator #2629

Merged
merged 10 commits into from
May 31, 2022
Merged
2 changes: 2 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,8 @@
* `BasisEmbedding` can accept an int as argument instead of a list of bits (optionally). Example: `qml.BasisEmbedding(4, wires = range(4))` is now equivalent to `qml.BasisEmbedding([0,1,0,0], wires = range(4))` (because 4=0b100).
[(#2601)](https://github.com/PennyLaneAI/pennylane/pull/2601)

* Introduced a new `is_hermitian` property to determine if an operator can be used in a measurement process.
[(#2629)](https://github.com/PennyLaneAI/pennylane/pull/2629)
<h3>Breaking changes</h3>

* The `qml.queuing.Queue` class is now removed.
Expand Down
6 changes: 3 additions & 3 deletions pennylane/measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,7 +463,7 @@ def circuit(x):
Raises:
QuantumFunctionError: `op` is not an instance of :class:`~.Observable`
"""
if not isinstance(op, (qml.operation.Observable, qml.Hamiltonian)):
if not op.is_hermitian:
raise qml.QuantumFunctionError(
f"{op.name} is not an observable: cannot be used with expval"
)
Expand Down Expand Up @@ -498,7 +498,7 @@ def circuit(x):
Raises:
QuantumFunctionError: `op` is not an instance of :class:`~.Observable`
"""
if not isinstance(op, qml.operation.Observable):
if not op.is_hermitian:
raise qml.QuantumFunctionError(f"{op.name} is not an observable: cannot be used with var")

return MeasurementProcess(Variance, obs=op, shape=(1,), numeric_type=float)
Expand Down Expand Up @@ -577,7 +577,7 @@ def circuit(x):
observable ``obs``.
"""
if (
not isinstance(op, qml.operation.Observable) and op is not None
op is not None and not op.is_hermitian
): # None type is also allowed for op
raise qml.QuantumFunctionError(
f"{op.name} is not an observable: cannot be used with sample"
Expand Down
10 changes: 10 additions & 0 deletions pennylane/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -1000,6 +1000,11 @@ def hyperparameters(self):
self._hyperparameters = {}
return self._hyperparameters

@property
def is_hermitian(self):
"""This property determines if an operator is hermitian."""
return False

def decomposition(self):
r"""Representation of the operator as a product of other operators.

Expand Down Expand Up @@ -1552,6 +1557,11 @@ def _queue_category(self):
"""
return "_ops" if isinstance(self, Operation) else None

@property
def is_hermitian(self):
"""All observables must be hermitian"""
return True

# pylint: disable=abstract-method
return_type = None
"""None or ObservableReturnTypes: Measurement type that this observable is called with."""
Expand Down
22 changes: 22 additions & 0 deletions tests/test_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -600,6 +600,17 @@ class DummyOp(qml.operation.Operation):
op = DummyOp(1.0, wires=0, id="test")
assert op.control_wires == qml.wires.Wires([])

def test_is_hermitian(self):
"""Test that is_hermitian defaults to False for an Operator"""

class DummyOp(qml.operation.Operation):
r"""Dummy custom operation"""
num_wires = 1
grad_method = None

op = DummyOp(wires=0)
assert op.is_hermitian is False


class TestObservableConstruction:
"""Test custom observables construction."""
Expand Down Expand Up @@ -711,6 +722,17 @@ class DummyObservable(qml.operation.Observable):
with pytest.raises(Exception, match="Must specify the wires *"):
DummyObservable()

def test_is_hermitian(self):
"""Test that the id attribute of an observable can be set."""

class DummyObserv(qml.operation.Observable):
r"""Dummy custom observable"""
num_wires = 1
grad_method = None

op = DummyObserv(wires=0)
assert op.is_hermitian is True


class TestOperatorIntegration:
"""Integration tests for the Operator class"""
Expand Down