Skip to content

Commit

Permalink
[OpRefactor] Use decomposition in templates (#2053)
Browse files Browse the repository at this point in the history
* decomposition and compute decomposition methods

* adding some more ops

* more consistent across qubit ops, return as tuple

* start adding templates

* move hyperparameters defintions

* update templates in a later PR

* tests

* fixing tests

* more test fixes

* final test fix!

* docstrings, interface device tests

* black, tests for coverage

* changelog and docstrings

* docstrings

* more child class docstrings

* Update doc/releases/changelog-dev.md

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

* nodecompositionerror, test new docstrings

* docstring fixes

* merge conflict

* docstring fixes and minor updates

* barrier doc change

* test fixing, parametric op docstrings

* final docstrings, black

* qft docstring

* black, fix test

* embeddings started to refactor

* embeddings done

* backup

* layers done

* statepreps done

* backup

* done subroutines

* backup

* fix tests except grover, timeevol, commuting

* black

* fix last three tests

* black

* black

* fix tests

* mottonnen fixed

* update changelog

* fixes, including sphinx

* backup

* Fix tape expand tests (#2065)

* fixes

* more

* more

* more

* more

* more

* more

* black

* delete faulty import

* improve codecoverage

* improve coverage by one line

* port one bug fix from other branch

* backup

* suggestions Josh 1

* redo changes in reset files

* rewrite op_list extension

* black

* fix tests

* change ttn

* make pylint happy

* black

* Apply suggestions from code review

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

Co-authored-by: albi3ro <chrissie.c.l@gmail.com>
Co-authored-by: Christina Lee <christina@xanadu.ai>
Co-authored-by: Josh Izaac <josh146@gmail.com>
Co-authored-by: Jay Soni <jbsoni@uwaterloo.ca>
  • Loading branch information
5 people committed Jan 20, 2022
1 parent 115a569 commit d7bfd12
Show file tree
Hide file tree
Showing 56 changed files with 1,873 additions and 941 deletions.
6 changes: 6 additions & 0 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,12 @@ The Operator class has undergone a major refactor with the following changes:
- By default, calling `op.generator()` does not take into account `op.inverse()`.
- If the generator is a single Pauli word, it is convenient to have access to
both the coefficient and the observable separately.

* Decompositions are now defined in `compute_decomposition`, instead of `expand`.
[(#2053)](https://github.com/PennyLaneAI/pennylane/pull/2053)

* The `expand` method was moved to the main `Operator` class.
[(#2053)](https://github.com/PennyLaneAI/pennylane/pull/2053)

* A `sparse_matrix` method and a `compute_sparse_matrix` static method were added
to the `Operator` class. The sparse representation of `SparseHamiltonian`
Expand Down
2 changes: 1 addition & 1 deletion pennylane/drawer/drawable_layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ def drawable_grid(ops, wire_map=None):
wire_map=None (dict): a map from wire label to non-negative integers
Returns:
List[List[~.Operator]] : layers compatible with grid objects
List[list[.Operator]] : layers compatible with grid objects
"""
if wire_map is None:
wire_map = default_wire_map(ops)
Expand Down
2 changes: 1 addition & 1 deletion pennylane/drawer/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def convert_wire_order(ops, wire_order=None, show_all_wires=False):
"""Creates the mapping between wire labels and place in order.
Args:
ops Iterable[~.Operator]: a list of operations
ops Iterable[.Operator]: a list of operations
wire_order Sequence[Any]: the order (from top to bottom) to print the wires
Keyword Args:
Expand Down
7 changes: 4 additions & 3 deletions pennylane/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,9 +922,10 @@ def decomposition(self):
>>> qml.IsingXX(1.23, wires=(0,1)).decomposition()
[CNOT(wires=[0, 1]), RX(1.23, wires=[0]), CNOT(wires=[0, 1])]
"""
return self.compute_decomposition(*self.parameters, self.wires, **self.hyperparameters)
return self.compute_decomposition(
*self.parameters, wires=self.wires, **self.hyperparameters
)

@staticmethod
def compute_decomposition(*params, wires=None, **hyperparameters):
Expand All @@ -937,7 +938,7 @@ def compute_decomposition(*params, wires=None, **hyperparameters):
``compute_decomposition`` is a static method and can provide the decomposition of an
operator without a specific instance.
See also :meth:`~.operation.Operator.decomposition`.
.. seealso:: :meth:`~.operation.Operator.decomposition`.
.. note::
This method gets overwritten by subclasses, and the ``decomposition`` and
Expand Down
4 changes: 2 additions & 2 deletions pennylane/ops/identity.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def label(self, decimals=None, base_label=None):
return base_label or "I"

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the Identity operator.
Returns:
Expand Down Expand Up @@ -104,7 +104,7 @@ def compute_decomposition(wires=None): # pylint:disable=arguments-differ,unused
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.Identity.decomposition`.
.. seealso:: :meth:`~.Identity.decomposition`.
Args:
wires (Any, Wires): A single wire that the operator acts on.
Expand Down
4 changes: 2 additions & 2 deletions pennylane/ops/qubit/arithmetic_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.QubitCarry.decomposition`.
.. seealso:: :meth:`~.QubitCarry.decomposition`.
Args:
wires (Iterable[Any], Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -280,7 +280,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.QubitSum.decomposition`.
.. seealso:: :meth:`~.QubitSum.decomposition`.
Args:
wires (Iterable[Any], Wires): Wires that the operator acts on.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/ops/qubit/hamiltonian.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ def compute_terms(*params, ops): # pylint: disable=arguments-differ
Args:
coeffs (Iterable[tensor_like or float]): coefficients
ops (list[~.Operator]): operators
ops (list[.Operator]): operators
Returns:
tuple[Iterable[tensor_like or float], list[.Operator]]: coefficients and operations
Expand Down
6 changes: 3 additions & 3 deletions pennylane/ops/qubit/matrix_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ def compute_decomposition(U, wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.QubitUnitary.decomposition`.
.. seealso:: :meth:`~.QubitUnitary.decomposition`.
A decomposition is only defined for matrices that act on either one or two wires. For more
than two wires, this method raises a ``DecompositionUndefined``.
Expand Down Expand Up @@ -353,7 +353,7 @@ def compute_matrix(D): # pylint: disable=arguments-differ
return qml.math.diag(D)

@staticmethod
def compute_eigvals(D): # pylint: disable=,arguments-differ
def compute_eigvals(D): # pylint: disable=arguments-differ
"""Eigenvalues of the DiagonalQubitUnitary operator.
Args:
Expand Down Expand Up @@ -384,7 +384,7 @@ def compute_decomposition(D, wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.DiagonalQubitUnitary.decomposition`.
.. seealso:: :meth:`~.DiagonalQubitUnitary.decomposition`.
``DiagonalQubitUnitary`` decomposes into :class:`~.QubitUnitary`, which has further
decompositions for one and two qubit matrices.
Expand Down
58 changes: 27 additions & 31 deletions pennylane/ops/qubit/non_parametric_ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[INV_SQRT2, INV_SQRT2], [INV_SQRT2, -INV_SQRT2]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the Hadamard operator.
Returns:
Expand Down Expand Up @@ -113,7 +113,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.Hadamard.decomposition`.
.. seealso:: :meth:`~.Hadamard.decomposition`.
Args:
wires (Any, Wires): Wire that the operator acts on.
Expand Down Expand Up @@ -184,7 +184,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[0, 1], [1, 0]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the PauliX operator.
Returns:
Expand Down Expand Up @@ -228,7 +228,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.PauliX.decomposition`.
.. seealso:: :meth:`~.PauliX.decomposition`.
Args:
wires (Any, Wires): Wire that the operator acts on.
Expand Down Expand Up @@ -302,7 +302,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[0, -1j], [1j, 0]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the PauliY operator.
Returns:
Expand Down Expand Up @@ -352,7 +352,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.PauliY.decomposition`.
.. seealso:: :meth:`~.PauliY.decomposition`.
Args:
wires (Any, Wires): Single wire that the operator acts on.
Expand Down Expand Up @@ -426,7 +426,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[1, 0], [0, -1]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the PauliZ operator.
Returns:
Expand Down Expand Up @@ -465,7 +465,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.PauliZ.decomposition`.
.. seealso:: :meth:`~.PauliZ.decomposition`.
Args:
wires (Any, Wires): Single wire that the operator acts on.
Expand Down Expand Up @@ -532,7 +532,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[1, 0], [0, 1j]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the S operator.
Returns:
Expand All @@ -554,7 +554,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.S.decomposition`.
.. seealso:: :meth:`~.S.decomposition`.
Args:
wires (Any, Wires): Single wire that the operator acts on.
Expand Down Expand Up @@ -618,7 +618,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[1, 0], [0, cmath.exp(1j * np.pi / 4)]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the T operator.
Returns:
Expand All @@ -640,7 +640,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.T.decomposition`.
.. seealso:: :meth:`~.T.decomposition`.
Args:
wires (Any, Wires): Single wire that the operator acts on.
Expand Down Expand Up @@ -704,7 +704,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return 0.5 * np.array([[1 + 1j, 1 - 1j], [1 - 1j, 1 + 1j]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the SX operator.
Returns:
Expand All @@ -726,7 +726,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.SX.decomposition`.
.. seealso:: :meth:`~.SX.decomposition`.
Args:
wires (Any, Wires): Single wire that the operator acts on.
Expand Down Expand Up @@ -867,7 +867,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, -1]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the CZ operator.
Returns:
Expand Down Expand Up @@ -953,7 +953,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.CY.decomposition`.
.. seealso:: :meth:`~.CY.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -1029,7 +1029,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.SWAP.decomposition`.
.. seealso:: :meth:`~.SWAP.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -1100,7 +1100,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
return np.array([[1, 0, 0, 0], [0, 0, 1j, 0], [0, 1j, 0, 0], [0, 0, 0, 1]])

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the ISWAP operator.
Returns:
Expand All @@ -1122,7 +1122,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.ISWAP.decomposition`.
.. seealso:: :meth:`~.ISWAP.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -1206,7 +1206,7 @@ def compute_matrix(): # pylint: disable=arguments-differ
)

@staticmethod
def compute_eigvals(): # pylint: disable=,arguments-differ
def compute_eigvals(): # pylint: disable=arguments-differ
"""Eigenvalues of the SISWAP operator.
Returns:
Expand All @@ -1228,7 +1228,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.SISWAP.decomposition`.
.. seealso:: :meth:`~.SISWAP.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -1352,7 +1352,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.CSWAP.decomposition`.
.. seealso:: :meth:`~.CSWAP.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -1458,7 +1458,7 @@ def compute_decomposition(wires):
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.Toffoli.decomposition`.
.. seealso:: :meth:`~.Toffoli.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on.
Expand Down Expand Up @@ -1573,7 +1573,6 @@ class MultiControlledX(Operation):
# pylint: disable=too-many-arguments
def __init__(
self,
*params,
control_wires=None,
wires=None,
control_values=None,
Expand Down Expand Up @@ -1615,7 +1614,7 @@ def compute_matrix(
"""Canonical matrix representation of the MultiControlledX operator.
Args:
control_wires (Iterable): wires to place controls on
control_wires (Any or Iterable[Any]): wires to place controls on
control_values (str): string of bits determining the controls
Returns:
Expand All @@ -1635,7 +1634,6 @@ def compute_matrix(
[0. 0. 0. 1.]]
"""

if control_values is None:
control_values = "1" * len(control_wires)

Expand Down Expand Up @@ -1668,7 +1666,6 @@ def adjoint(self):
control_wires=self.wires[:-1],
wires=self.wires[-1],
control_values=self.hyperparameters["control_values"],
work_wires=self.hyperparameters["work_wires"],
)

@staticmethod
Expand All @@ -1680,11 +1677,10 @@ def compute_decomposition(wires=None, work_wires=None, control_values=None, **kw
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.MultiControlledX.decomposition`.
.. seealso:: :meth:`~.MultiControlledX.decomposition`.
Args:
wires (Iterable, Wires): Wires that the operator acts on. Should contain both control wires
and target wire. Target wire is the last wire in the Iterable.
wires (Iterable[Any] or Wires): wires that the operation acts on
work_wires (Wires): optional work wires used to decompose
the operation into a series of Toffoli gates.
control_values (str): a string of bits representing the state of the control
Expand Down Expand Up @@ -1852,7 +1848,7 @@ def compute_decomposition(wires, only_visual=False): # pylint: disable=unused-a
``compute_decomposition`` is a static method and can provide the decomposition of a given
operator without creating a specific instance.
See also :meth:`~.Barrier.decomposition`.
.. seealso:: :meth:`~.Barrier.decomposition`.
``Barrier`` decomposes into an empty list for all arguments.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/ops/qubit/observables.py
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@ def compute_matrix(basis_state): # pylint: disable=arguments-differ
return m

@staticmethod
def compute_eigvals(basis_state): # pylint: disable=,arguments-differ
def compute_eigvals(basis_state): # pylint: disable=arguments-differ
"""Eigenvalues of the Projector operator.
Args:
Expand Down
Loading

0 comments on commit d7bfd12

Please sign in to comment.