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

Add LTensor Hermitian wire length check #806

Merged
merged 7 commits into from
Jul 18, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@

### Bug fixes

* Check for the number of wires for Hermitian observables in Lightning-Tensor. Only 1-wire Hermitian observables are supported as of `cuTensorNet-v24.03.0`.
[(#806)](https://github.com/PennyLaneAI/pennylane-lightning/pull/806)

* Set `PL_BACKEND` for the entire `build-wheel-lightning-gpu` Docker-build stage to properly build the Lightning-GPU wheel.
[(#791)](https://github.com/PennyLaneAI/pennylane-lightning/pull/791)

Expand Down
2 changes: 1 addition & 1 deletion pennylane_lightning/core/_version.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@
Version number (major.minor.patch[-label])
"""

__version__ = "0.38.0-dev10"
__version__ = "0.38.0-dev11"
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#include "Constant.hpp"
#include "ConstantUtil.hpp" // lookup
#include "Error.hpp"
#include "Util.hpp"

#include "cuda_helpers.hpp"
Expand Down Expand Up @@ -241,6 +242,8 @@ class HermitianObsTNCuda : public ObservableTNCuda<TensorNetT> {
*/
HermitianObsTNCuda(MatrixT matrix, std::vector<std::size_t> wires)
: matrix_{std::move(matrix)}, wires_{std::move(wires)} {
PL_ABORT_IF(wires_.size() != 1, "The number of Hermitian target wires "
"must be 1 for Lightning-Tensor.");
PL_ASSERT(matrix_.size() == Pennylane::Util::exp2(2 * wires_.size()));
BaseType::coeffs_.emplace_back(PrecisionT{1.0});
BaseType::numTensors_.emplace_back(std::size_t{1});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,16 +86,18 @@ TEMPLATE_TEST_CASE("[Hermitian]", "[Observables]", float, double) {
using HermitianObsT = HermitianObsTNCuda<TensorNetT>;

SECTION("HermitianObs only accepts correct arguments") {
auto ob1 =
HermitianObsT{std::vector<ComplexT>{0.0, 0.0, 0.0, 0.0}, {0}};
auto ob2 = HermitianObsT{std::vector<ComplexT>(16, ComplexT{}), {0, 1}};
REQUIRE_THROWS_AS(
HermitianObsT(std::vector<ComplexT>{0.0, 0.0, 0.0}, {0}),
LightningException);
REQUIRE_THROWS_AS(
HermitianObsT(std::vector<ComplexT>{0.0, 0.0, 0.0, 0.0, 0.0},
{0, 1}),
LightningException);
REQUIRE_THROWS_WITH(
HermitianObsT(std::vector<ComplexT>(16, ComplexT{0.0, 0.0}),
{0, 1}),
Catch::Matchers::Contains("The number of Hermitian target wires "
"must be 1 for Lightning-Tensor."));
}

SECTION("Test get obs name") {
Expand Down Expand Up @@ -153,8 +155,8 @@ TEMPLATE_TEST_CASE("[TensorProd]", "[Observables]", float, double) {

SECTION("Overlapping wires throw an exception") {
auto ob1 = std::make_shared<HermitianObsT>(
std::vector<ComplexT>(16, ComplexT{0.0, 0.0}),
std::vector<std::size_t>{0, 1});
std::vector<ComplexT>(4, ComplexT{0.0, 0.0}),
std::vector<std::size_t>{1});
auto ob2_1 = std::make_shared<NamedObsT>(
"PauliX", std::vector<std::size_t>{1});
auto ob2_2 = std::make_shared<NamedObsT>(
Expand All @@ -167,8 +169,8 @@ TEMPLATE_TEST_CASE("[TensorProd]", "[Observables]", float, double) {

SECTION("Constructing an observable with non-overlapping wires ") {
auto ob1 = std::make_shared<HermitianObsT>(
std::vector<ComplexT>(16, ComplexT{0.0, 0.0}),
std::vector<std::size_t>{0, 1});
std::vector<ComplexT>(4, ComplexT{0.0, 0.0}),
std::vector<std::size_t>{1});
auto ob2_1 = std::make_shared<NamedObsT>(
"PauliX", std::vector<std::size_t>{2});
auto ob2_2 = std::make_shared<NamedObsT>(
Expand Down
4 changes: 4 additions & 0 deletions pennylane_lightning/lightning_tensor/_measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,10 @@
if isinstance(measurementprocess.obs, qml.SparseHamiltonian):
raise NotImplementedError("Sparse Hamiltonians are not supported.")

if isinstance(measurementprocess.obs, qml.Hermitian):
if len(measurementprocess.obs.wires) > 1:
raise ValueError("The number of Hermitian observables target wires should be 1.")

Check warning on line 79 in pennylane_lightning/lightning_tensor/_measurements.py

View check run for this annotation

Codecov / codecov/patch

pennylane_lightning/lightning_tensor/_measurements.py#L77-L79

Added lines #L77 - L79 were not covered by tests

ob_serialized = QuantumScriptSerializer(
self._tensornet.device_name, self.dtype == np.complex64
)._ob(measurementprocess.obs)
Expand Down
18 changes: 15 additions & 3 deletions tests/test_expval.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ def circuit():
circ_def = qml.QNode(circuit, dev_def)
assert np.allclose(circ(), circ_def(), tol)

@pytest.mark.parametrize("n_wires", range(1, 7 if device_name != "lightning.tensor" else 5))
@pytest.mark.parametrize("n_wires", range(1, 7))
def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol):
"""Test that Hermitian expectation value is correct"""
n_qubits = 7
Expand All @@ -185,14 +185,26 @@ def test_hermitian_expectation(self, n_wires, theta, phi, qubit_device, tol):
def circuit():
if device_name != "lightning.tensor":
qml.StatePrep(init_state, wires=range(n_qubits))
qml.RY(theta, wires=[0])
qml.RX(theta, wires=[0])
qml.RY(phi, wires=[1])
qml.RX(theta, wires=[2])
qml.RY(phi, wires=[3])
qml.RX(theta, wires=[4])
qml.RY(phi, wires=[5])
qml.RX(theta, wires=[6])
qml.CNOT(wires=[0, 1])
return qml.expval(obs)

circ = qml.QNode(circuit, dev)
circ_def = qml.QNode(circuit, dev_def)
assert np.allclose(circ(), circ_def(), tol)
if device_name == "lightning.tensor" and n_wires > 1:
with pytest.raises(
ValueError,
match="The number of Hermitian observables target wires should be 1.",
):
assert np.allclose(circ(), circ_def(), tol)
else:
assert np.allclose(circ(), circ_def(), tol)


@pytest.mark.parametrize(
Expand Down
Loading