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

Remove complex warning from operator matrices #1802

Merged
merged 11 commits into from
Oct 27, 2021
7 changes: 6 additions & 1 deletion pennylane/devices/default_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -487,6 +487,7 @@ def expval(self, observable, shot_range=None, bin_size=None):
# Compute <psi| H |psi> via sum_i coeff_i * <psi| PauliWord |psi> using a sparse
# representation of the Pauliword
res = qml.math.cast(qml.math.convert_like(0.0, observable.data), dtype=complex)
interface = qml.math.get_interface(self.state)

# Note: it is important that we use the Hamiltonian's data and not the coeffs attribute.
# This is because the .data attribute may be 'unwrapped' as required by the interfaces,
Expand All @@ -502,7 +503,11 @@ def expval(self, observable, shot_range=None, bin_size=None):
* Hmat
* qml.math.gather(self.state, coo.col)
)
c = qml.math.cast(qml.math.convert_like(coeff, product), "complex128")
c = qml.math.convert_like(coeff, product)

if interface == "tensorflow":
c = qml.math.cast(c, "complex128")
Comment on lines +508 to +509
Copy link
Member Author

Choose a reason for hiding this comment

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

I tracked down another complex warning here. @glassnotes, I fear more are hiding still 😆

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm very confused about this one, is it not doing the exact same thing but in two lines? Or does doing the casting in the other frameworks spit out a warning while tensorflow does not? 😕

Copy link
Member Author

Choose a reason for hiding this comment

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

Yep! during the backwards pass, the reverse will happen - a complex value will be cast to real. Which... generates the warning in PyTorch and Autograd 🤦

Copy link
Contributor

Choose a reason for hiding this comment

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

🤦‍♀️ indeed


res = qml.math.convert_like(res, product) + qml.math.sum(c * product)

else:
Expand Down
55 changes: 28 additions & 27 deletions pennylane/ops/qubit/parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,9 @@ def _matrix(cls, *params):

js = -1j * s

return qml.math.stack([qml.math.stack([c, js]), qml.math.stack([js, c])])
return qml.math.diag([c, c]) + qml.math.stack(
[qml.math.stack([0, js]), qml.math.stack([js, 0])]
)

def adjoint(self):
return RX(-self.data[0], wires=self.wires)
Expand Down Expand Up @@ -122,7 +124,9 @@ def _matrix(cls, *params):
c = qml.math.cos(theta / 2)
s = qml.math.sin(theta / 2)

return qml.math.stack([qml.math.stack([c, -s]), qml.math.stack([s, c])])
return qml.math.diag([c, c]) + qml.math.stack(
[qml.math.stack([0, -s]), qml.math.stack([s, 0])]
)

def adjoint(self):
return RY(-self.data[0], wires=self.wires)
Expand Down Expand Up @@ -838,18 +842,23 @@ def label(self, decimals=None, base_label=None):
@classmethod
def _matrix(cls, *params):
theta = params[0]
interface = qml.math.get_interface(theta)

c = qml.math.cos(theta / 2)
s = qml.math.sin(theta / 2)
z = qml.math.zeros([4], like=interface)

if qml.math.get_interface(theta) == "tensorflow":
if interface == "tensorflow":
c = qml.math.cast_like(c, 1j)
s = qml.math.cast_like(s, 1j)
z = qml.math.cast_like(z, 1j)

js = -1j * s

mat = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, c, js], [0, 0, js, c]]
return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([1, 1, c, c])
return mat + qml.math.stack(
[z, z, qml.math.stack([0, 0, 0, js]), qml.math.stack([0, 0, js, 0])]
)

@staticmethod
def decomposition(theta, wires):
Expand Down Expand Up @@ -928,12 +937,16 @@ def label(self, decimals=None, base_label=None):
@classmethod
def _matrix(cls, *params):
theta = params[0]
interface = qml.math.get_interface(theta)

c = qml.math.cos(theta / 2)
s = qml.math.sin(theta / 2)
z = qml.math.zeros([4], like=interface)

mat = [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, c, -s], [0, 0, s, c]]
return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([1, 1, c, c])
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this necessary here, since CRY is purely real?

Copy link
Member Author

Choose a reason for hiding this comment

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

weirdly yes, for the same reason that OrbitalRotation also raises the warning. I'm not entirely sure why this is an issue though?? So weird.

return mat + qml.math.stack(
[z, z, qml.math.stack([0, 0, 0, -s]), qml.math.stack([0, 0, s, 0])]
)

@staticmethod
def decomposition(theta, wires):
Expand Down Expand Up @@ -1396,20 +1409,15 @@ def _matrix(cls, *params):

c = qml.math.cos(phi / 2)
s = qml.math.sin(phi / 2)
Y = qml.math.convert_like(np.eye(4)[::-1].copy(), phi)

if qml.math.get_interface(phi) == "tensorflow":
c = qml.math.cast_like(c, 1j)
s = qml.math.cast_like(s, 1j)
Y = qml.math.cast_like(Y, 1j)

js = -1j * s

mat = [
[c, 0, 0, js],
[0, c, js, 0],
[0, js, c, 0],
[js, 0, 0, c],
]

return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([c, c, c, c]) - 1j * s * Y
return mat

@staticmethod
def decomposition(phi, wires):
Expand Down Expand Up @@ -1471,21 +1479,14 @@ def _matrix(cls, *params):

c = qml.math.cos(phi / 2)
s = qml.math.sin(phi / 2)
Y = qml.math.convert_like(np.diag([1, -1, -1, 1])[::-1].copy(), phi)

if qml.math.get_interface(phi) == "tensorflow":
c = qml.math.cast_like(c, 1j)
s = qml.math.cast_like(s, 1j)
Y = qml.math.cast_like(Y, 1j)

js = 1j * s

mat = [
[c, 0.0, 0.0, js],
[0.0, c, -js, 0.0],
[0.0, -js, c, 0.0],
[js, 0.0, 0.0, c],
]

return qml.math.stack([qml.math.stack(row) for row in mat])
return qml.math.diag([c, c, c, c]) + 1j * s * Y

def adjoint(self):
(phi,) = self.parameters
Expand Down
94 changes: 25 additions & 69 deletions pennylane/ops/qubit/qchem_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,9 @@ def _matrix(cls, *params):
c = qml.math.cos(theta / 2)
s = qml.math.sin(theta / 2)

mat = [[1, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, 1]]
return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([1, c, c, 1])
off_diag = qml.math.convert_like(np.diag([0, 1, -1, 0])[::-1].copy(), theta)
return mat + s * qml.math.cast_like(off_diag, s)

@staticmethod
def decomposition(theta, wires):
Expand Down Expand Up @@ -163,9 +164,9 @@ def _matrix(cls, *params):
s = qml.math.cast_like(s, 1j)

e = qml.math.exp(-1j * theta / 2)

mat = [[e, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, e]]
return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([e, 0, 0, e]) + qml.math.diag([0, c, c, 0])
off_diag = qml.math.convert_like(np.diag([0, 1, -1, 0])[::-1].copy(), theta)
return mat + s * qml.math.cast_like(off_diag, s)

@staticmethod
def decomposition(theta, wires):
Expand Down Expand Up @@ -238,9 +239,9 @@ def _matrix(cls, *params):
s = qml.math.cast_like(s, 1j)

e = qml.math.exp(1j * theta / 2)

mat = [[e, 0, 0, 0], [0, c, -s, 0], [0, s, c, 0], [0, 0, 0, e]]
return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([e, 0, 0, e]) + qml.math.diag([0, c, c, 0])
off_diag = qml.math.convert_like(np.diag([0, 1, -1, 0])[::-1].copy(), theta)
return mat + s * qml.math.cast_like(off_diag, s)

@staticmethod
def decomposition(theta, wires):
Expand Down Expand Up @@ -332,26 +333,10 @@ def _matrix(cls, *params):
c = qml.math.cos(theta / 2)
s = qml.math.sin(theta / 2)

mat = [
[1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, c, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -s, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, c, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
]

return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([1.0] * 3 + [c] + [1.0] * 8 + [c] + [1.0] * 3)
mat = qml.math.scatter_element_add(mat, (3, 12), -s)
mat = qml.math.scatter_element_add(mat, (12, 3), s)
return mat

@staticmethod
def decomposition(theta, wires):
Expand Down Expand Up @@ -454,26 +439,12 @@ def _matrix(cls, *params):

e = qml.math.exp(1j * theta / 2)

mat = [
[e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, c, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -s, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, c, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e],
]

return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([e] * 3 + [0] + [e] * 8 + [0] + [e] * 3)
mat = qml.math.scatter_element_add(mat, (3, 3), c)
mat = qml.math.scatter_element_add(mat, (3, 12), -s)
mat = qml.math.scatter_element_add(mat, (12, 3), s)
mat = qml.math.scatter_element_add(mat, (12, 12), c)
return mat

def adjoint(self):
(theta,) = self.parameters
Expand Down Expand Up @@ -539,27 +510,12 @@ def _matrix(cls, *params):
s = qml.math.cast_like(s, 1j)

e = qml.math.exp(-1j * theta / 2)

mat = [
[e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, c, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, -s, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, s, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, c, 0.0, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e, 0.0],
[0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, e],
]

return qml.math.stack([qml.math.stack(row) for row in mat])
mat = qml.math.diag([e] * 3 + [0] + [e] * 8 + [0] + [e] * 3)
mat = qml.math.scatter_element_add(mat, (3, 3), c)
mat = qml.math.scatter_element_add(mat, (3, 12), -s)
mat = qml.math.scatter_element_add(mat, (12, 3), s)
mat = qml.math.scatter_element_add(mat, (12, 12), c)
return mat

def adjoint(self):
(theta,) = self.parameters
Expand Down
2 changes: 1 addition & 1 deletion tests/ops/qubit/test_hamiltonian.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
try:
import torch

COEFFS_PARAM_INTERFACE.append((torch.tensor([-0.05, 0.17]), torch.tensor([1.7]), "torch"))
COEFFS_PARAM_INTERFACE.append((torch.tensor([-0.05, 0.17]), torch.tensor(1.7), "torch"))
josh146 marked this conversation as resolved.
Show resolved Hide resolved
except ImportError:
pass

Expand Down