Skip to content

Commit

Permalink
Adjoint operator modifiers (#2222)
Browse files Browse the repository at this point in the history
* add adjoint and inverse operator modifiers

* updates

* updates

* imports

* add testing and docs

* adding tests

* queuing fix

* constructor func

* more tests, differentiability

* working on tests passing

* stash

* testing

* tests

* tests, move adjoint method to operator

* create arithmetic module

* fix import paths

* move back to ops/arithmetic, fix more tests

* tests

* more tests and some documentation

* tiny fixes

* Update pattern matching

* add lazy keyword

* add some tests and revert some things [skip ci]

* rename to op_math, dynamically add mixin

* tidying

* polishing

* polishing

* some minor fixes

* trying to figure out in place inversion [skip ci]

* trying to figure out in place inversion [skip ci]

* fixing tests

* fix tests, changelog

* final tests, changelog

* Apply suggestions from code review

Co-authored-by: Maria Schuld <mariaschuld@gmail.com>

* oops

* trying to fix documentation

* Update pennylane/templates/subroutines/hilbert_schmidt.py

Co-authored-by: Maria Schuld <mariaschuld@gmail.com>

* formatting, use safe_update_queue

* Apply suggestions from code review

Co-authored-by: Maria Schuld <mariaschuld@gmail.com>
Co-authored-by: Josh Izaac <josh146@gmail.com>

* _wires getter and setter, _single_op_eager keyword

* oops

* private _wires test

* Update tests/ops/op_math/test_adjoint_transform.py

Co-authored-by: Maria Schuld <mariaschuld@gmail.com>

* Apply suggestions from code review

Co-authored-by: Jay Soni <jbsoni@uwaterloo.ca>

* respond to code review

* oops

* complete code coverage

* black

Co-authored-by: Romain Moyard <rmoyard@gmail.com>
Co-authored-by: Maria Schuld <mariaschuld@gmail.com>
Co-authored-by: Josh Izaac <josh146@gmail.com>
Co-authored-by: Jay Soni <jbsoni@uwaterloo.ca>
  • Loading branch information
5 people committed Jun 3, 2022
1 parent 85cc93f commit bbbe6ff
Show file tree
Hide file tree
Showing 47 changed files with 1,758 additions and 1,190 deletions.
40 changes: 33 additions & 7 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,39 @@
tensor([0.69301172, 0.67552491, 0.65128847], requires_grad=True)
```

**Operator Arithmetic:**

* The adjoint transform `adjoint` can now accept either a single instantiated operator or
a quantum function. It returns an entity of the same type/ call signature as what it was given:
[(#2222)](https://github.com/PennyLaneAI/pennylane/pull/2222)

```pycon
>>> qml.adjoint(qml.PauliX(0))
Adjoint(PauliX)(wires=[0])
>>> qml.adjoint(lambda x: qml.RX(x, wires=0))(1.23)
Adjoint(RX)(1.23, wires=[0])
```

The adjoint now wraps operators in a symbolic operator class `qml.ops.op_math.Adjoint`. This class
should not be constructed directly; the `adjoint` constructor should always be used instead. The
class behaves just like any other Operator:

```pycon
>>> op = qml.adjoint(qml.S(0))
>>> qml.matrix(op)
array([[1.-0.j, 0.-0.j],
[0.-0.j, 0.-1.j]])
>>> qml.eigvals(op)
array([1.-0.j, 0.-1.j])
```

* The unused keyword argument `do_queue` for `Operation.adjoint` is now fully removed.
[(#2583)](https://github.com/PennyLaneAI/pennylane/pull/2583)

* The developer-facing `pow` method has been added to `Operator` with concrete implementations
for many classes.
[(#2225)](https://github.com/PennyLaneAI/pennylane/pull/2225)

<h3>Improvements</h3>

* IPython displays the `str` representation of a `Hamiltonian`, rather than the `repr`. This displays
Expand All @@ -183,10 +216,6 @@
one place and remove their dependency to openfermion.
[(#2593)](https://github.com/PennyLaneAI/pennylane/pull/2593)

* The developer-facing `pow` method has been added to `Operator` with concrete implementations
for many classes.
[(#2225)](https://github.com/PennyLaneAI/pennylane/pull/2225)

* Test classes are created in qchem test modules to group the integrals and matrices unittests.
[(#2545)](https://github.com/PennyLaneAI/pennylane/pull/2545)

Expand Down Expand Up @@ -248,9 +277,6 @@
* The `qml.queuing.Queue` class is now removed.
[(#2599)](https://github.com/PennyLaneAI/pennylane/pull/2599)

* The unused keyword argument `do_queue` for `Operation.adjoint` is now fully removed.
[(#2583)](https://github.com/PennyLaneAI/pennylane/pull/2583)

* The module `qml.gradients.param_shift_hessian` has been renamed to
`qml.gradients.parameter_shift_hessian` in order to distinguish it from the identically named
function. Note that the `param_shift_hessian` function is unaffected by this change and can be
Expand Down
2 changes: 1 addition & 1 deletion pennylane/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
from pennylane.io import *
from pennylane.measurements import density_matrix, measure, expval, probs, sample, state, var
from pennylane.ops import *
from pennylane.ops import adjoint
from pennylane.templates import broadcast, layer
from pennylane.templates.embeddings import *
from pennylane.templates.layers import *
Expand All @@ -55,7 +56,6 @@
from pennylane import qaoa
from pennylane.qnode import QNode, qnode
from pennylane.transforms import (
adjoint,
adjoint_metric_tensor,
batch_params,
batch_input,
Expand Down
5 changes: 5 additions & 0 deletions pennylane/devices/default_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,17 @@ class DefaultQubit(QubitDevice):
"MultiRZ",
"Hadamard",
"S",
"Adjoint(S)",
"T",
"Adjoint(T)",
"SX",
"Adjoint(SX)",
"CNOT",
"SWAP",
"ISWAP",
"Adjoint(ISWAP)",
"SISWAP",
"Adjoint(SISWAP)",
"SQISW",
"CSWAP",
"Toffoli",
Expand Down
1 change: 0 additions & 1 deletion pennylane/devices/default_qubit_torch.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,6 @@ def circuit(x):
)
_transpose = staticmethod(lambda a, axes=None: a.permute(*axes))
_asnumpy = staticmethod(lambda x: x.cpu().numpy())
_conj = staticmethod(torch.conj)
_real = staticmethod(torch.real)
_imag = staticmethod(torch.imag)
_norm = staticmethod(torch.norm)
Expand Down
17 changes: 11 additions & 6 deletions pennylane/math/single_dispatch.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@ def _i(name):
return import_module(name)


# -------------------------------- SciPy --------------------------------- #
# the following is required to ensure that SciPy sparse Hamiltonians passed to
# qml.SparseHamiltonian are not automatically 'unwrapped' to dense NumPy arrays.
ar.register_function("scipy", "to_numpy", lambda x: x)

ar.register_function("scipy", "shape", np.shape)
ar.register_function("scipy", "conj", np.conj)
ar.register_function("scipy", "transpose", np.transpose)
ar.register_function("scipy", "ndim", np.ndim)


# -------------------------------- NumPy --------------------------------- #
from scipy.linalg import block_diag as _scipy_block_diag

Expand All @@ -44,12 +55,6 @@ def _i(name):
ar.register_function("numpy", "unstack", list)
ar.register_function("builtins", "unstack", list)

# the following is required to ensure that SciPy sparse Hamiltonians passed to
# qml.SparseHamiltonian are not automatically 'unwrapped' to dense NumPy arrays.
ar.register_function("scipy", "to_numpy", lambda x: x)
ar.register_function("scipy", "shape", np.shape)
ar.register_function("scipy", "ndim", np.ndim)


def _scatter_element_add_numpy(tensor, index, value):
"""In-place addition of a multidimensional value over various
Expand Down
34 changes: 16 additions & 18 deletions pennylane/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,8 +510,7 @@ def __copy__(self):
return copied_op

def __deepcopy__(self, memo):
cls = self.__class__
copied_op = cls.__new__(cls)
copied_op = object.__new__(type(self))

# The memo dict maps object ID to object, and is required by
# the deepcopy function to keep track of objects it has already
Expand Down Expand Up @@ -1164,6 +1163,21 @@ def _queue_category(self):
"""
return "_ops"

def adjoint(self): # pylint:disable=no-self-use
"""Create an operation that is the adjoint of this one.
Adjointed operations are the conjugated and transposed version of the
original operation. Adjointed ops are equivalent to the inverted operation for unitary
gates.
Args:
do_queue: Whether to add the adjointed gate to the context queue.
Returns:
The adjointed operation.
"""
raise AdjointUndefinedError

def expand(self):
"""Returns a tape that has recorded the decomposition of the operator.
Expand Down Expand Up @@ -1280,7 +1294,6 @@ def control_wires(self): # pragma: no cover
"""
return Wires([])

@property
def single_qubit_rot_angles(self):
r"""The parameters required to implement a single-qubit gate as an
equivalent ``Rot`` gate, up to a global phase.
Expand Down Expand Up @@ -1383,21 +1396,6 @@ def inverse(self):
"""Boolean determining if the inverse of the operation was requested."""
return self._inverse

def adjoint(self): # pylint:disable=no-self-use
"""Create an operation that is the adjoint of this one.
Adjointed operations are the conjugated and transposed version of the
original operation. Adjointed ops are equivalent to the inverted operation for unitary
gates.
Args:
do_queue: Whether to add the adjointed gate to the context queue.
Returns:
The adjointed operation.
"""
raise AdjointUndefinedError

@inverse.setter
def inverse(self, boolean):
self._inverse = boolean
Expand Down
6 changes: 2 additions & 4 deletions pennylane/ops/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
This module contains core quantum operations supported by PennyLane -
such as gates, state preparations and observables.
"""
from .op_math import adjoint

from .cv import *
from .qubit import *
from .channel import *
Expand All @@ -33,10 +35,6 @@
from .channel import __all__ as _channel__ops__


class AdjointError(Exception):
"""Exception for non-adjointable operations."""


__all__ = _cv__all__ + _qubit__all__ + _channel__ops__
__all_ops__ = list(_cv__ops__ | _qubit__ops__)
__all_obs__ = list(_cv__obs__ | _qubit__obs__)
24 changes: 24 additions & 0 deletions pennylane/ops/op_math/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Copyright 2018-2022 Xanadu Quantum Technologies Inc.

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at

# http://www.apache.org/licenses/LICENSE-2.0

# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""
This module contains classes and functions for Operator arithmetic.
.. currentmodule:: pennylane.ops.op_math
.. autosummary::
:toctree: api
"""

from .adjoint_class import Adjoint
from .adjoint_constructor import adjoint
Loading

0 comments on commit bbbe6ff

Please sign in to comment.