Skip to content

Commit 75dfecb

Browse files
Add Projector Obs to LGPU (#894)
### Before submitting Please complete the following checklist when submitting a PR: - [ ] All new features must include a unit test. If you've fixed a bug or added code that should be tested, add a test to the [`tests`](../tests) directory! - [ ] All new functions and code must be clearly commented and documented. If you do make documentation changes, make sure that the docs build and render correctly by running `make docs`. - [ ] Ensure that the test suite passes, by running `make test`. - [ ] Add a new entry to the `.github/CHANGELOG.md` file, summarizing the change, and including a link back to the PR. - [ ] Ensure that code is properly formatted by running `make format`. When all the above are checked, delete everything above the dashed line and fill in the pull request template. ------------------------------------------------------------------------------------------------------------ **Context:** Add support for `Projector` observable via diagonalization to LGPU. **Description of the Change:** **Benefits:** **Possible Drawbacks:** **Related GitHub Issues:** Fixes #883 [sc-72652] --------- Co-authored-by: ringo-but-quantum <[email protected]>
1 parent a36fe22 commit 75dfecb

File tree

6 files changed

+25
-9
lines changed

6 files changed

+25
-9
lines changed

.github/CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
### New features since last release
44

5+
* Add `Projector` observable support via diagonalization to Lightning-GPU.
6+
[(#894)](https://github.com/PennyLaneAI/pennylane-lightning/pull/894)
7+
58
* Add 1-target wire controlled gate support to `lightning.tensor`. Note that `cutensornet` only supports 1-target wire controlled gate as of `v24.08`. A controlled gate with more than 1 target wire should be converted to dense matrix.
69
[(#880)](https://github.com/PennyLaneAI/pennylane-lightning/pull/880)
710

doc/lightning_gpu/device.rst

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ Supported operations and observables
104104
~pennylane.PauliX
105105
~pennylane.PauliY
106106
~pennylane.PauliZ
107+
~pennylane.Projector
107108
~pennylane.Hermitian
108109
~pennylane.Hamiltonian
109110
~pennylane.SparseHamiltonian

pennylane_lightning/core/_version.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@
1616
Version number (major.minor.patch[-label])
1717
"""
1818

19-
__version__ = "0.39.0-dev10"
19+
__version__ = "0.39.0-dev11"

pennylane_lightning/lightning_gpu/lightning_gpu.py

+19
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ def _mebibytesToBytes(mebibytes):
187187
"LinearCombination",
188188
"Hermitian",
189189
"Identity",
190+
"Projector",
190191
"Sum",
191192
"Prod",
192193
"SProd",
@@ -804,6 +805,15 @@ def expval(self, observable, shot_range=None, bin_size=None):
804805
Returns:
805806
Expectation value of the observable
806807
"""
808+
if isinstance(observable, qml.Projector):
809+
diagonalizing_gates = observable.diagonalizing_gates()
810+
if self.shots is None and diagonalizing_gates:
811+
self.apply(diagonalizing_gates)
812+
results = super().expval(observable, shot_range=shot_range, bin_size=bin_size)
813+
if self.shots is None and diagonalizing_gates:
814+
self.apply([qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)])
815+
return results
816+
807817
if self.shots is not None:
808818
# estimate the expectation value
809819
samples = self.sample(observable, shot_range=shot_range, bin_size=bin_size)
@@ -887,6 +897,15 @@ def var(self, observable, shot_range=None, bin_size=None):
887897
Returns:
888898
Variance of the observable
889899
"""
900+
if isinstance(observable, qml.Projector):
901+
diagonalizing_gates = observable.diagonalizing_gates()
902+
if self.shots is None and diagonalizing_gates:
903+
self.apply(diagonalizing_gates)
904+
results = super().var(observable, shot_range=shot_range, bin_size=bin_size)
905+
if self.shots is None and diagonalizing_gates:
906+
self.apply([qml.adjoint(g, lazy=False) for g in reversed(diagonalizing_gates)])
907+
return results
908+
890909
if self.shots is not None:
891910
# estimate the var
892911
# Lightning doesn't support sampling yet

tests/test_expval.py

-3
Original file line numberDiff line numberDiff line change
@@ -106,9 +106,6 @@ def test_projector_expectation(self, theta, phi, qubit_device, tol):
106106
dev_def = qml.device("default.qubit", wires=n_qubits)
107107
dev = qubit_device(wires=n_qubits)
108108

109-
if "Projector" not in dev.observables:
110-
pytest.skip("Device does not support the Projector observable.")
111-
112109
init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits)
113110
init_state /= np.linalg.norm(init_state)
114111
obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1])

tests/test_var.py

+1-5
Original file line numberDiff line numberDiff line change
@@ -50,19 +50,15 @@ def test_var(self, theta, phi, qubit_device, tol):
5050

5151
assert np.allclose(var, expected, tol)
5252

53-
pytest.mark.skipif(
53+
@pytest.mark.skipif(
5454
device_name == "lightning.tensor", reason="lightning.tensor doesn't support projector."
5555
)
56-
5756
def test_projector_var(self, theta, phi, qubit_device, tol):
5857
"""Test that Projector variance value is correct"""
5958
n_qubits = 2
6059
dev_def = qml.device("default.qubit", wires=n_qubits)
6160
dev = qubit_device(wires=n_qubits)
6261

63-
if "Projector" not in dev.observables:
64-
pytest.skip("Device does not support the Projector observable.")
65-
6662
init_state = np.random.rand(2**n_qubits) + 1j * np.random.rand(2**n_qubits)
6763
init_state /= np.linalg.norm(init_state)
6864
obs = qml.Projector(np.array([0, 1, 0, 0]) / np.sqrt(2), wires=[0, 1])

0 commit comments

Comments
 (0)