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

Make numerical representations of operators differentiable #1749

Merged
merged 40 commits into from
Oct 18, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
1960665
Convert most parametric ops to use qml.math.
Oct 13, 2021
8a1b084
Run black.
Oct 13, 2021
4c26d23
Use stack for everything. Update helper functions.
Oct 14, 2021
a93d794
Remove operations that have been converted.
Oct 14, 2021
56b4d9e
Update single excitations and devices.
Oct 14, 2021
9f3231e
Black utils.
Oct 14, 2021
0b8ece6
Update all devices to use the default operations.
Oct 14, 2021
b460a68
Remove empty dict.
Oct 14, 2021
0c8779b
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
glassnotes Oct 14, 2021
64a9c25
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
josh146 Oct 14, 2021
c1a8de5
Remove get unitary matrix from devices where not needed.
Oct 14, 2021
91c924f
Apply suggestions from code review
glassnotes Oct 14, 2021
22e14df
Update pennylane/ops/qubit/parametric_ops.py
josh146 Oct 14, 2021
ca6bad7
fix
josh146 Oct 14, 2021
5295a0a
fix
josh146 Oct 14, 2021
7c17da9
linting
josh146 Oct 14, 2021
9872936
fix torch errors
josh146 Oct 14, 2021
91be029
fix torch errors
josh146 Oct 14, 2021
177445d
fix tf errors
josh146 Oct 14, 2021
dc23908
Fix failing torch GPU test.
Oct 14, 2021
6e2f426
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
josh146 Oct 15, 2021
5d44213
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
Oct 15, 2021
37c5627
Remove ops files.
Oct 15, 2021
d6f3643
Update CHANGELOG.
Oct 15, 2021
b576ca4
Temporary commit.
Oct 15, 2021
bc54d6c
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
glassnotes Oct 16, 2021
b9fa516
Remove checks on theta shape.
glassnotes Oct 16, 2021
9ab79a7
Fix incorrect parameters in tensorflow section.
glassnotes Oct 16, 2021
9acb2f4
merge master
josh146 Oct 18, 2021
d9d58ca
fix tests
josh146 Oct 18, 2021
e504cfd
fix tests
josh146 Oct 18, 2021
438bc17
fix
josh146 Oct 18, 2021
4a78be2
Fix matrix op and add speedup with 1j mult.
glassnotes Oct 18, 2021
82b1731
Add missing tests.
glassnotes Oct 18, 2021
716f811
Fix tensor dimensions.
glassnotes Oct 18, 2021
6583f1d
Update changelog. Add missing eigval test.
glassnotes Oct 18, 2021
ed16fa0
Run black.
glassnotes Oct 18, 2021
29a6da2
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
josh146 Oct 18, 2021
83b9b0b
Apply suggestions from code review
glassnotes Oct 18, 2021
310c2ec
Merge branch 'master' into sc-7223-numerical-representations-of-opera…
glassnotes Oct 18, 2021
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
54 changes: 0 additions & 54 deletions pennylane/devices/default_qubit_autograd.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@
from pennylane import numpy as np

from pennylane.devices import DefaultQubit
from pennylane.devices import autograd_ops


class DefaultQubitAutograd(DefaultQubit):
Expand Down Expand Up @@ -81,30 +80,6 @@ class DefaultQubitAutograd(DefaultQubit):
name = "Default qubit (Autograd) PennyLane plugin"
short_name = "default.qubit.autograd"

parametric_ops = {
"PhaseShift": autograd_ops.PhaseShift,
"ControlledPhaseShift": autograd_ops.ControlledPhaseShift,
"CPhase": autograd_ops.ControlledPhaseShift,
"RX": autograd_ops.RX,
"RY": autograd_ops.RY,
"RZ": autograd_ops.RZ,
"Rot": autograd_ops.Rot,
"CRX": autograd_ops.CRX,
"CRY": autograd_ops.CRY,
"CRZ": autograd_ops.CRZ,
"CRot": autograd_ops.CRot,
"MultiRZ": autograd_ops.MultiRZ,
"IsingXX": autograd_ops.IsingXX,
"IsingYY": autograd_ops.IsingYY,
"IsingZZ": autograd_ops.IsingZZ,
"SingleExcitation": autograd_ops.SingleExcitation,
"SingleExcitationPlus": autograd_ops.SingleExcitationPlus,
"SingleExcitationMinus": autograd_ops.SingleExcitationMinus,
"DoubleExcitation": autograd_ops.DoubleExcitation,
"DoubleExcitationPlus": autograd_ops.DoubleExcitationPlus,
"DoubleExcitationMinus": autograd_ops.DoubleExcitationMinus,
}

C_DTYPE = np.complex128
R_DTYPE = np.float64
_dot = staticmethod(np.dot)
Expand Down Expand Up @@ -154,32 +129,3 @@ def _scatter(indices, array, new_dimensions):
new_array = np.zeros(new_dimensions, dtype=array.dtype.type)
new_array[indices] = array
return new_array

def _get_unitary_matrix(self, unitary):
"""Return the matrix representing a unitary operation.

Args:
unitary (~.Operation): a PennyLane unitary operation

Returns:
array[complex]: Returns a 2D matrix representation of
the unitary in the computational basis, or, in the case of a diagonal unitary,
a 1D array representing the matrix diagonal.
"""
op_name = unitary.name.split(".inv")[0]

if op_name in self.parametric_ops:
if op_name == "MultiRZ":
mat = self.parametric_ops[op_name](*unitary.parameters, len(unitary.wires))
else:
mat = self.parametric_ops[op_name](*unitary.parameters)

if unitary.inverse:
mat = self._transpose(self._conj(mat))

return mat

if isinstance(unitary, DiagonalOperation):
return unitary.eigvals

return unitary.matrix
54 changes: 0 additions & 54 deletions pennylane/devices/default_qubit_jax.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@
import pennylane as qml
from pennylane.operation import DiagonalOperation
from pennylane.devices import DefaultQubit
from pennylane.devices import jax_ops
Copy link
Member

Choose a reason for hiding this comment

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

🎉


import numpy as np

Expand Down Expand Up @@ -133,30 +132,6 @@ def circuit():
name = "Default qubit (jax) PennyLane plugin"
short_name = "default.qubit.jax"

parametric_ops = {
"PhaseShift": jax_ops.PhaseShift,
"ControlledPhaseShift": jax_ops.ControlledPhaseShift,
"CPhase": jax_ops.ControlledPhaseShift,
"RX": jax_ops.RX,
"RY": jax_ops.RY,
"RZ": jax_ops.RZ,
"Rot": jax_ops.Rot,
"CRX": jax_ops.CRX,
"CRY": jax_ops.CRY,
"CRZ": jax_ops.CRZ,
"CRot": jax_ops.CRot,
"MultiRZ": jax_ops.MultiRZ,
"IsingXX": jax_ops.IsingXX,
"IsingYY": jax_ops.IsingYY,
"IsingZZ": jax_ops.IsingZZ,
"SingleExcitation": jax_ops.SingleExcitation,
"SingleExcitationPlus": jax_ops.SingleExcitationPlus,
"SingleExcitationMinus": jax_ops.SingleExcitationMinus,
"DoubleExcitation": jax_ops.DoubleExcitation,
"DoubleExcitationPlus": jax_ops.DoubleExcitationPlus,
"DoubleExcitationMinus": jax_ops.DoubleExcitationMinus,
}

_asarray = staticmethod(jnp.array)
_dot = staticmethod(jnp.dot)
_abs = staticmethod(jnp.abs)
Expand Down Expand Up @@ -208,35 +183,6 @@ def _scatter(indices, array, new_dimensions):
new_array = new_array.at[indices].set(array)
return new_array

def _get_unitary_matrix(self, unitary):
"""Return the matrix representing a unitary operation.

Args:
unitary (~.Operation): a PennyLane unitary operation

Returns:
array[complex]: Returns a 2D matrix representation of
the unitary in the computational basis, or, in the case of a diagonal unitary,
a 1D array representing the matrix diagonal.
"""
op_name = unitary.name.split(".inv")[0]

if op_name in self.parametric_ops:
if op_name == "MultiRZ":
mat = self.parametric_ops[op_name](*unitary.parameters, len(unitary.wires))
else:
mat = self.parametric_ops[op_name](*unitary.parameters)

if unitary.inverse:
mat = self._transpose(self._conj(mat))

return mat

if isinstance(unitary, DiagonalOperation):
return unitary.eigvals

return unitary.matrix

def sample_basis_states(self, number_of_states, state_probability):
"""Sample from the computational basis states based on the state
probability.
Expand Down
56 changes: 0 additions & 56 deletions pennylane/devices/default_qubit_tf.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
pass

from . import DefaultQubit
from . import tf_ops


class DefaultQubitTF(DefaultQubit):
Expand Down Expand Up @@ -129,30 +128,6 @@ class DefaultQubitTF(DefaultQubit):
name = "Default qubit (TensorFlow) PennyLane plugin"
short_name = "default.qubit.tf"

parametric_ops = {
"PhaseShift": tf_ops.PhaseShift,
"ControlledPhaseShift": tf_ops.ControlledPhaseShift,
"CPhase": tf_ops.ControlledPhaseShift,
"RX": tf_ops.RX,
"RY": tf_ops.RY,
"RZ": tf_ops.RZ,
"Rot": tf_ops.Rot,
"MultiRZ": tf_ops.MultiRZ,
"CRX": tf_ops.CRX,
"CRY": tf_ops.CRY,
"CRZ": tf_ops.CRZ,
"CRot": tf_ops.CRot,
"IsingXX": tf_ops.IsingXX,
"IsingYY": tf_ops.IsingYY,
"IsingZZ": tf_ops.IsingZZ,
"SingleExcitation": tf_ops.SingleExcitation,
"SingleExcitationPlus": tf_ops.SingleExcitationPlus,
"SingleExcitationMinus": tf_ops.SingleExcitationMinus,
"DoubleExcitation": tf_ops.DoubleExcitation,
"DoubleExcitationPlus": tf_ops.DoubleExcitationPlus,
"DoubleExcitationMinus": tf_ops.DoubleExcitationMinus,
}

C_DTYPE = tf.complex128
R_DTYPE = tf.float64
_asarray = staticmethod(tf.convert_to_tensor)
Expand Down Expand Up @@ -209,34 +184,3 @@ def capabilities(cls):
def _scatter(indices, array, new_dimensions):
indices = np.expand_dims(indices, 1)
return tf.scatter_nd(indices, array, new_dimensions)

def _get_unitary_matrix(self, unitary):
"""Return the matrix representing a unitary operation.

Args:
unitary (~.Operation): a PennyLane unitary operation

Returns:
tf.Tensor[complex] or array[complex]: Returns a 2D matrix representation of
the unitary in the computational basis, or, in the case of a diagonal unitary,
a 1D array representing the matrix diagonal. For non-parametric unitaries,
the return type will be a ``np.ndarray``. For parametric unitaries, a ``tf.Tensor``
object will be returned.
"""
op_name = unitary.name.split(".inv")[0]

if op_name in self.parametric_ops:
if op_name == "MultiRZ":
mat = self.parametric_ops[op_name](*unitary.parameters, len(unitary.wires))
else:
mat = self.parametric_ops[op_name](*unitary.parameters)

if unitary.inverse:
mat = self._transpose(self._conj(mat))

return mat

if isinstance(unitary, DiagonalOperation):
return unitary.eigvals

return unitary.matrix
39 changes: 0 additions & 39 deletions pennylane/devices/default_qubit_torch.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@

import numpy as np
from pennylane.operation import DiagonalOperation
from pennylane.devices import torch_ops
from . import DefaultQubit


Expand Down Expand Up @@ -132,29 +131,6 @@ def circuit(x):
name = "Default qubit (Torch) PennyLane plugin"
short_name = "default.qubit.torch"

parametric_ops = {
"PhaseShift": torch_ops.PhaseShift,
"ControlledPhaseShift": torch_ops.ControlledPhaseShift,
"RX": torch_ops.RX,
"RY": torch_ops.RY,
"RZ": torch_ops.RZ,
"MultiRZ": torch_ops.MultiRZ,
"Rot": torch_ops.Rot,
"CRX": torch_ops.CRX,
"CRY": torch_ops.CRY,
"CRZ": torch_ops.CRZ,
"CRot": torch_ops.CRot,
"IsingXX": torch_ops.IsingXX,
"IsingYY": torch_ops.IsingYY,
"IsingZZ": torch_ops.IsingZZ,
"SingleExcitation": torch_ops.SingleExcitation,
"SingleExcitationPlus": torch_ops.SingleExcitationPlus,
"SingleExcitationMinus": torch_ops.SingleExcitationMinus,
"DoubleExcitation": torch_ops.DoubleExcitation,
"DoubleExcitationPlus": torch_ops.DoubleExcitationPlus,
"DoubleExcitationMinus": torch_ops.DoubleExcitationMinus,
}

C_DTYPE = torch.complex128
R_DTYPE = torch.float64

Expand Down Expand Up @@ -261,21 +237,6 @@ def _get_unitary_matrix(self, unitary):
the unitary in the computational basis, or, in the case of a diagonal unitary,
a 1D array representing the matrix diagonal.
"""
op_name = unitary.base_name
if op_name in self.parametric_ops:
if op_name == "MultiRZ":
mat = self.parametric_ops[op_name](
*unitary.parameters, len(unitary.wires), device=self._torch_device
)
else:
mat = self.parametric_ops[op_name](*unitary.parameters, device=self._torch_device)
if unitary.inverse:
if isinstance(unitary, DiagonalOperation):
mat = self._conj(mat)
else:
mat = self._transpose(self._conj(mat), axes=[1, 0])
return mat

if isinstance(unitary, DiagonalOperation):
return self._asarray(unitary.eigvals, dtype=self.C_DTYPE)
return self._asarray(unitary.matrix, dtype=self.C_DTYPE)
Expand Down
1 change: 1 addition & 0 deletions pennylane/math/single_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ def _take_autograd(tensor, indices, axis=None):
ar.autoray._SUBMODULE_ALIASES["tensorflow", "arctan2"] = "tensorflow.math"
ar.autoray._SUBMODULE_ALIASES["tensorflow", "diag"] = "tensorflow.linalg"
ar.autoray._SUBMODULE_ALIASES["tensorflow", "kron"] = "tensorflow.experimental.numpy"
ar.autoray._SUBMODULE_ALIASES["tensorflow", "moveaxis"] = "tensorflow.experimental.numpy"
Copy link
Member

Choose a reason for hiding this comment

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

this is the only one that needed to be added? I'm somewhat surprised (in a good way), I thought more would be needed



ar.autoray._FUNC_ALIASES["tensorflow", "arcsin"] = "asin"
Expand Down
6 changes: 3 additions & 3 deletions pennylane/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,7 +767,7 @@ def matrix(self):
op_matrix = self._matrix(*self.parameters)

if self.inverse:
return op_matrix.conj().T
return qml.math.conj(qml.math.T(op_matrix))

return op_matrix

Expand All @@ -776,7 +776,7 @@ def eigvals(self):
op_eigvals = self._eigvals(*self.parameters)

if self.inverse:
return op_eigvals.conj()
return qml.math.conj(op_eigvals)

return op_eigvals

Expand Down Expand Up @@ -1886,6 +1886,6 @@ def operation_derivative(operation) -> np.ndarray:

if operation.inverse:
prefactor *= -1
generator = generator.conj().T
generator = qml.math.conj(qml.math.T(generator))

return 1j * prefactor * generator @ operation.matrix
Loading