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

Use pauli_rep to compute qml.matrix() whenever possible #5392

Closed
wants to merge 36 commits into from
Closed
Show file tree
Hide file tree
Changes from 32 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ff3e6ea
Updated condition for swapping matmul order
mudit2812 Mar 4, 2024
08b681e
Added tests
mudit2812 Mar 4, 2024
b1c4391
use pauli rep for computing matrix of Sum
Qottmann Mar 15, 2024
a90a15b
[ci skip]
Qottmann Mar 15, 2024
8a78e44
black formatting
Qottmann Mar 22, 2024
98202cf
black formatting
Qottmann Mar 22, 2024
a6a5de0
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
Qottmann Mar 26, 2024
bc04197
changelog
Qottmann Mar 26, 2024
0c359f5
Merge branch 'master' into summatrix
Qottmann Apr 3, 2024
d43fc1d
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
Qottmann Apr 4, 2024
c5b869f
upgrade qml.matrix
Qottmann Apr 4, 2024
7e2b7f3
black formatting
Qottmann Apr 4, 2024
88f746e
remove changes to matrix
Qottmann Apr 4, 2024
93b3ac2
Merge branch 'pauli-swap-order' of https://github.com/PennyLaneAI/pen…
Qottmann Apr 4, 2024
54f642b
branch off mudits PR
Qottmann Apr 4, 2024
86bb86b
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
Qottmann Apr 4, 2024
9580c13
merge
Qottmann Apr 4, 2024
7b317db
bugfix
Qottmann Apr 5, 2024
e77a606
Merge branch 'master' of https://github.com/PennyLaneAI/pennylane int…
Qottmann Apr 5, 2024
c063fbb
[ci skip]
Qottmann Apr 5, 2024
d4ddba2
Merge branch 'master' into pauli-swap-order
mudit2812 Apr 9, 2024
58efe4c
[skip ci] Skip CI
mudit2812 Apr 9, 2024
56111e4
Merge branch 'master' into pauli-swap-order
mudit2812 Apr 9, 2024
4786179
[skip ci] Skip CI
mudit2812 Apr 9, 2024
e4cb275
Merge branch 'master' into pauli-swap-order
mudit2812 Apr 11, 2024
d209151
Merge branch 'master' into pauli-swap-order
mudit2812 Apr 17, 2024
743996e
Merge branch 'master' into pauli-swap-order
mudit2812 Apr 18, 2024
64af1ca
Fixed failing tests
mudit2812 Apr 18, 2024
6f16caa
Trigger CI
mudit2812 Apr 18, 2024
a618920
Updated qasm test
mudit2812 Apr 18, 2024
60bb55e
Merge branch 'master' into pauli-swap-order
mudit2812 Apr 18, 2024
50f8ae6
Merge branch 'pauli-swap-order' into summatrix
mudit2812 Apr 18, 2024
cbc3cad
remove commented code
Qottmann Apr 19, 2024
4bc3072
merge
Qottmann Apr 24, 2024
460243f
merge changelog
Qottmann Apr 24, 2024
2d76378
merge
Qottmann Apr 24, 2024
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
7 changes: 4 additions & 3 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,13 +223,14 @@
[stim](https://github.com/quantumlib/Stim) `v1.13.0`.
[(#5409)](https://github.com/PennyLaneAI/pennylane/pull/5409)

* `Sum.matrix` and `Prod.matrix` use the pauli representation for matrix computation,
which results in faster computation of the matrix.
[(5392)](https://github.com/PennyLaneAI/pennylane/pull/5392)

* `qml.specs` and `qml.Tracker` now return information about algorithmic errors for the qnode as well.
[(#5464)](https://github.com/PennyLaneAI/pennylane/pull/5464)
[(#5465)](https://github.com/PennyLaneAI/pennylane/pull/5465)

* `qml.specs` now returns information regarding algorithmic errors for the qnode as well.
[(#5464)](https://github.com/PennyLaneAI/pennylane/pull/5464)

* `qml.transforms.hamiltonian_expand` can now handle multi-term observables with a constant offset.
[(#5414)](https://github.com/PennyLaneAI/pennylane/pull/5414)

Expand Down
4 changes: 3 additions & 1 deletion pennylane/ops/functions/matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,8 +211,10 @@ def circuit():
if isinstance(op, qml.operation.Tensor) and wire_order is not None:
op = 1.0 * op # convert to a Hamiltonian

if isinstance(op, qml.ops.Hamiltonian):
if (pr := op.pauli_rep) is not None:
return pr.to_mat(wire_order=wire_order or op.wires, format="csr").toarray()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is CSR what we want to use for this?

Copy link
Contributor Author

@Qottmann Qottmann Apr 24, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For context, this came up in switching to new opmath because some generators and qchem operators where now slower in computing qml.matrix(), as they were no longer ops.Hamiltonian instances and therefore didnt hit the op.sparse_matrix(..).toarray() method below anymore. The idea was to just allow still doing that via the pauli rep in this PR; but as @albi3ro pointed out this breaks differentiability. Afaik christina has been cooking up an alternate solution 👩‍🍳


if isinstance(op, qml.ops.Hamiltonian):
return op.sparse_matrix(wire_order=wire_order).toarray()

try:
Expand Down
3 changes: 3 additions & 0 deletions pennylane/ops/op_math/prod.py
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,9 @@ def decomposition(self):
def matrix(self, wire_order=None):
"""Representation of the operator as a matrix in the computational basis."""

# if self.pauli_rep: # Get the matrix from the PauliSentence representation
# return self.pauli_rep.to_mat(wire_order=wire_order or self.wires, format="csr").toarray()
Qottmann marked this conversation as resolved.
Show resolved Hide resolved

mats: List[TensorLike] = []
batched: List[bool] = [] # batched[i] tells if mats[i] is batched or not
for ops in self.overlapping_ops:
Expand Down
3 changes: 3 additions & 0 deletions pennylane/ops/op_math/sum.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,9 @@ def matrix(self, wire_order=None):
Returns:
tensor_like: matrix representation
"""
# if self.pauli_rep: # Get the matrix from the PauliSentence representation
# return self.pauli_rep.to_mat(wire_order=wire_order or self.wires, format="csr").toarray()
Qottmann marked this conversation as resolved.
Show resolved Hide resolved

gen = (
(qml.matrix(op) if isinstance(op, qml.ops.Hamiltonian) else op.matrix(), op.wires)
for op in self
Expand Down
2 changes: 1 addition & 1 deletion pennylane/pauli/pauli_arithmetic.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ def __hash__(self):
def _matmul(self, other):
"""Private matrix multiplication that returns (pauli_word, coeff) tuple for more lightweight processing"""
base, iterator, swapped = (
(self, other, False) if len(self) > len(other) else (other, self, True)
(self, other, False) if len(self) >= len(other) else (other, self, True)
)
result = copy(dict(base))
coeff = 1
Expand Down
6 changes: 3 additions & 3 deletions tests/circuit_graph/test_qasm.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,9 +117,9 @@ def test_to_ApproxTimeEvolution(self):
include "qelib1.inc";
qreg q[2];
creg c[2];
cx q[0],q[1];
rz(2.0) q[1];
cx q[0],q[1];
cx q[1],q[0];
rz(2.0) q[0];
cx q[1],q[0];
measure q[0] -> c[0];
measure q[1] -> c[1];
"""
Expand Down
4 changes: 2 additions & 2 deletions tests/ops/functions/test_matrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -569,8 +569,8 @@ def circuit():
qml.matrix(circuit, wire_order=wires)()

with pytest.raises(
TransformError,
match=r"Wires in circuit \[0\] are inconsistent with those in wire_order \[1\]",
ValueError,
match=r"the matrix for the specified wire order because it does not contain all the Pauli sentence",
):
qml.matrix(qml.PauliX(0), wire_order=[1])

Expand Down
15 changes: 12 additions & 3 deletions tests/ops/op_math/test_prod.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,15 @@ def test_terms_pauli_rep(self, op, coeffs_true, ops_true):
assert coeffs == coeffs_true
assert ops1 == ops_true

def test_terms_pauli_rep_wire_order(self):
"""Test that the wire order of the terms is the same as the wire order of the original
operands when the Prod has a valid pauli_rep"""
H = qml.prod(X(0), X(1), X(2))
_, H_ops = H.terms()

assert len(H_ops) == 1
assert H_ops[0].wires == H.wires

def test_batch_size(self):
"""Test that batch size returns the batch size of a base operation if it is batched."""
x = qml.numpy.array([1.0, 2.0, 3.0])
Expand Down Expand Up @@ -1035,8 +1044,8 @@ def test_pauli_rep_order(self):
"""
op = qml.prod(qml.PauliX(0), qml.PauliY(1), qml.PauliZ(2))
pw = list(op.pauli_rep.keys())[0]
assert list(pw.keys()) == [1, 0, 2]
assert list(pw.values()) == ["Y", "X", "Z"]
assert list(pw.keys()) == [0, 1, 2]
assert list(pw.values()) == ["X", "Y", "Z"]

@pytest.mark.parametrize("op, rep", op_pauli_reps)
def test_pauli_rep(self, op, rep):
Expand Down Expand Up @@ -1119,7 +1128,7 @@ def test_simplify_method_product_of_sums(self):
"""Test the simplify method with a product of sums."""
prod_op = Prod(qml.PauliX(0) + qml.RX(1, 0), qml.PauliX(1) + qml.RX(1, 1), qml.Identity(3))
final_op = qml.sum(
Prod(qml.PauliX(1), qml.PauliX(0)),
Prod(qml.PauliX(0), qml.PauliX(1)),
qml.PauliX(0) @ qml.RX(1, 1),
qml.PauliX(1) @ qml.RX(1, 0),
qml.RX(1, 0) @ qml.RX(1, 1),
Expand Down
18 changes: 18 additions & 0 deletions tests/ops/op_math/test_sum.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,24 @@ def test_terms_pauli_rep(self, op, coeffs_true, ops_true):
assert coeffs == coeffs_true
assert ops1 == ops_true

def test_terms_pauli_rep_wire_order(self):
"""Test that the wire order of the terms is the same as the wire order of the original
operands when the Sum has a valid pauli_rep"""
w0, w1, w2, w3 = [0, 1, 2, 3]
coeffs = [0.5, -0.5]

obs = [
qml.X(w0) @ qml.Y(w1) @ qml.X(w2) @ qml.Z(w3),
qml.X(w0) @ qml.X(w1) @ qml.Y(w2) @ qml.Z(w3),
]

H = qml.dot(coeffs, obs)
_, H_ops = H.terms()

assert all(o1.wires == o2.wires for o1, o2 in zip(obs, H_ops))
assert H_ops[0] == qml.prod(qml.X(w0), qml.Y(w1), qml.X(w2), qml.Z(w3))
assert H_ops[1] == qml.prod(qml.X(w0), qml.X(w1), qml.Y(w2), qml.Z(w3))

coeffs_ = [1.0, 1.0, 1.0, 3.0, 4.0, 4.0, 5.0]
h6 = qml.sum(
qml.s_prod(2.0, qml.prod(qml.Hadamard(0), qml.PauliZ(10))),
Expand Down
2 changes: 1 addition & 1 deletion tests/pauli/test_measurement_transformations.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ def test_diagonalize_pauli_word_catch_non_pauli_word(self, non_pauli_word):
(
[PauliX(0) @ PauliY(1), PauliX(0) @ PauliZ(2)],
(
[RX(np.pi / 2, wires=[1]), RY(-np.pi / 2, wires=[0])],
[RY(-np.pi / 2, wires=[0]), RX(np.pi / 2, wires=[1])],
[PauliZ(wires=[0]) @ PauliZ(wires=[1]), PauliZ(wires=[0]) @ PauliZ(wires=[2])],
),
),
Expand Down
5 changes: 1 addition & 4 deletions tests/pauli/test_pauli_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -926,10 +926,7 @@ def test_diagonalize_pauli_word_catch_non_pauli_word(self, non_pauli_word):
(
[PauliX(0) @ PauliY(1), PauliX(0) @ PauliZ(2)],
(
[
RX(np.pi / 2, wires=[1]),
RY(-np.pi / 2, wires=[0]),
],
[RY(-np.pi / 2, wires=[0]), RX(np.pi / 2, wires=[1])],
[PauliZ(wires=[0]) @ PauliZ(wires=[1]), PauliZ(wires=[0]) @ PauliZ(wires=[2])],
),
),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ class TestDecomposition:
),
(
2,
qml.Hamiltonian([2, 0.5], [qml.PauliX("a"), qml.PauliZ("b") @ qml.PauliX("a")]),
qml.Hamiltonian([2, 0.5], [qml.PauliX("a"), qml.PauliX("a") @ qml.PauliZ("b")]),
2,
[
qml.PauliRot(4.0, "X", wires=["a"]),
Expand All @@ -87,7 +87,7 @@ class TestDecomposition:
[2, 0.5, 0.5],
[
qml.PauliX("a"),
qml.PauliZ(-15) @ qml.PauliX("a"),
qml.PauliX("a") @ qml.PauliZ(-15),
qml.Identity(0) @ qml.PauliY(-15),
],
),
Expand Down
18 changes: 9 additions & 9 deletions tests/test_qaoa.py
Original file line number Diff line number Diff line change
Expand Up @@ -1166,12 +1166,12 @@ def make_mixer_layer_test_cases():
[
qaoa.xy_mixer(Graph([(0, 1), (1, 2), (2, 0)])),
[
qml.PauliRot(1.0, "XX", wires=[1, 0]),
qml.PauliRot(1.0, "YY", wires=[1, 0]),
qml.PauliRot(1.0, "XX", wires=[2, 0]),
qml.PauliRot(1.0, "YY", wires=[2, 0]),
qml.PauliRot(1.0, "XX", wires=[2, 1]),
qml.PauliRot(1.0, "YY", wires=[2, 1]),
qml.PauliRot(1.0, "XX", wires=[0, 1]),
qml.PauliRot(1.0, "YY", wires=[0, 1]),
qml.PauliRot(1.0, "XX", wires=[0, 2]),
qml.PauliRot(1.0, "YY", wires=[0, 2]),
qml.PauliRot(1.0, "XX", wires=[1, 2]),
qml.PauliRot(1.0, "YY", wires=[1, 2]),
],
],
]
Expand All @@ -1186,9 +1186,9 @@ def make_cost_layer_test_cases():
[
qaoa.maxcut(Graph([(0, 1), (1, 2), (2, 0)]))[0],
[
qml.PauliRot(1.0, "ZZ", wires=[1, 0]),
qml.PauliRot(1.0, "ZZ", wires=[2, 0]),
qml.PauliRot(1.0, "ZZ", wires=[2, 1]),
qml.PauliRot(1.0, "ZZ", wires=[0, 1]),
qml.PauliRot(1.0, "ZZ", wires=[0, 2]),
qml.PauliRot(1.0, "ZZ", wires=[1, 2]),
],
],
]
Expand Down
Loading