Skip to content

Commit

Permalink
qml.evolve: dispatch function (#3706)
Browse files Browse the repository at this point in the history
* 🧪 tests (evolve): Fix tests.

* 📝 docs (evolve): Fix docstring.

* 📝 docs (evolve): Fix docstring.

* 🧪 tests (evolve): Add tests.

* ✏️ chore (changelog): Add changelog entry.

* 📝 docs (evolve): Fix docstring.

* 📝 docs (evolve): Fix docstring.

* 🧪 tests (evolve): Fix coverage.

* 🔧 refactor (evolve): Dispatch function.

* 🔧 refactor (evolve): Dispatch function.

* 📝 docs (evolve): Fix docstring.

* 🧪 tests (evolve): Fix tests.

* 📝 docs (evolve): Fix sphinx.

* ⏪ revert (evolve): Remove t and dt from parametrized_evolution.

* 📝 docs (evolve): Fix docstring.

* 📝 docs (evolve): Fix docstring.

* Update pennylane/ops/functions/evolve.py

Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com>

* Update pennylane/ops/functions/evolve.py

Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com>

* 📝 docs (evolve): Update evolve docstring.

* 📝 docs (evolve): Update evolve docstring.

* 📝 docs (evolve): Fix sphinx.

* 📝 docs (evolve): Test sphinx.

* 📝 docs (evolve): Test sphinx.

* 📝 docs (evolve): Use html.

* 📝 docs (evolve): Fix docstring.

* 📝 docs (evolve): Fix docstring.

* 📝 docs (evolve): Test sphinx.

* 📝 docs (evolve): Test sphinx.

* 📝 docs (evolve): Fix docstring.

* 📝 docs (evolve): Fix docstring.

* 🐛 fix (evolve): Remove op from initial call.

* 📝 docs (evolve): Remove docstrings of dispatched functions.

* 📝 docs (evolve): Change docstring.

* 🔧 refactor (evolve): Add warning.

* Update doc/releases/changelog-dev.md

* ✏️ chore (changelog): Add deprecation entry.

* ✏️ chore (changelog): Add changelog entry.

* 📝 docs (evolve): Change docstring.

* Update pennylane/ops/functions/evolve.py

---------

Co-authored-by: lillian542 <38584660+lillian542@users.noreply.github.com>
  • Loading branch information
AlbertMitjans and lillian542 authored Feb 6, 2023
1 parent 8f84d07 commit 0995dc9
Show file tree
Hide file tree
Showing 7 changed files with 95 additions and 30 deletions.
6 changes: 6 additions & 0 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ Pending deprecations
- Deprecated in v0.29.
- Will be removed in v0.31.

* A warning has been added in ``Evolution`` redirecting users to ``qml.evolve``. This was added
because we want to change the behaviour of ``Evolution``, adding a ``-1`` to the given parameter.

- Deprecated in v0.29.
- Will be removed in v0.30.

Completed deprecation cycles
----------------------------

Expand Down
12 changes: 9 additions & 3 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,11 @@

* A `ParametrizedHamiltonian` can be time-evolved by using `ParametrizedEvolution`.
[(#3617)](https://github.com/PennyLaneAI/pennylane/pull/3617)
[(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

* A new function called `qml.evolve` has been added that returns the evolution of an operator or a `ParametrizedHamiltonian`.
* A new function called `qml.evolve` has been added that returns the evolution of an `Operator` or a `ParametrizedHamiltonian`.
[(#3617)](https://github.com/PennyLaneAI/pennylane/pull/3617)
[(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

* A new function `dot` has been added to compute the dot product between a vector and a list of operators. `qml.dot` will now target this new function.
[(#3586)](https://github.com/PennyLaneAI/pennylane/pull/3586)
Expand All @@ -71,8 +73,8 @@
* The Hadamard test gradient tranform is now available via `qml.gradients.hadamard_grad`.
[#3625](https://github.com/PennyLaneAI/pennylane/pull/3625)

`qml.gradients.hadamard_grad` is a hardware-compatible transform that calculates the
gradient of a quantum circuit using the Hadamard test. Note that the device requires an
`qml.gradients.hadamard_grad` is a hardware-compatible transform that calculates the
gradient of a quantum circuit using the Hadamard test. Note that the device requires an
auxiliary wire to calculate the gradient.

```pycon
Expand Down Expand Up @@ -478,6 +480,10 @@
* `qml.op_sum` has been deprecated. Users should use `qml.sum` instead.
[(#3686)](https://github.com/PennyLaneAI/pennylane/pull/3686)

* The use of `Evolution` directly has been deprecated. Users should use `qml.evolve` instead.
This new function changes the sign of the given parameter.
[(#3706)](https://github.com/PennyLaneAI/pennylane/pull/3706)

<h3>Documentation</h3>

* Organizes the module for documentation for ``operation``.
Expand Down
70 changes: 57 additions & 13 deletions pennylane/ops/functions/evolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,32 +14,64 @@
"""
This module contains the qml.evolve function.
"""
from typing import Union
import warnings
from functools import singledispatch

from pennylane.operation import Operator
from pennylane.ops import Evolution
from pennylane.pulse import ParametrizedEvolution, ParametrizedHamiltonian


def evolve(op: Union[Operator, ParametrizedHamiltonian]):
"""Returns a new operator that computes the evolution of ``op``.
@singledispatch
def evolve(*args, **kwargs): # pylint: disable=unused-argument
r"""This method is dispatched and its functionality depends on the type of the input ``op``.
.. raw:: html
<html>
<h3>Input: Operator</h3>
<hr>
</html>
Returns a new operator that computes the evolution of ``op``.
.. math::
e^{-i x \bm{O}}
Args:
op (Union[.Operator, .ParametrizedHamiltonian]): operator to evolve
op (.Operator): operator to evolve
coeff (float): coefficient multiplying the exponentiated operator
Returns:
Union[.Evolution, ~pennylane.ops.op_math.evolve.ParametrizedEvolution]: evolution operator
.Evolution: evolution operator
.. seealso:: :class:`.ParametrizedEvolution`
.. seealso:: :class:`.Evolution`
.. seealso:: :class:`~.Evolution`
**Examples**
We can use ``qml.evolve`` to compute the evolution of any PennyLane operator:
>>> op = qml.s_prod(2, qml.PauliX(0))
>>> qml.evolve(op)
Exp(1j 2*(PauliX(wires=[0])))
>>> op = qml.evolve(qml.PauliX(0), coeff=2)
>>> op
Exp(2j PauliX)
.. raw:: html
<html>
<h3>Input: ParametrizedHamiltonian</h3>
<hr>
</html>
Args:
op (.ParametrizedHamiltonian): operator to evolve
Returns:
~pennylane.ops.op_math.evolve.ParametrizedEvolution: evolution operator
.. seealso:: :class:`.ParametrizedEvolution`
**Examples**
When evolving a :class:`.ParametrizedHamiltonian` class, then a :class:`.ParametrizedEvolution`
instance is returned:
Expand All @@ -58,7 +90,19 @@ def evolve(op: Union[Operator, ParametrizedHamiltonian]):
Please check the :class:`.ParametrizedEvolution` class for more information.
"""
if isinstance(op, ParametrizedHamiltonian):
return ParametrizedEvolution(H=op)

return Evolution(generator=op, param=1.0)

# pylint: disable=missing-docstring
@evolve.register
def parametrized_hamiltonian(op: ParametrizedHamiltonian):
return ParametrizedEvolution(H=op)


# pylint: disable=missing-docstring
@evolve.register
def evolution(op: Operator, coeff: float = 1):
with warnings.catch_warnings():
# Ignore the warning raised in `Evolution`
warnings.simplefilter("ignore")
ev = Evolution(op, -1 * coeff)
return ev
6 changes: 5 additions & 1 deletion pennylane/ops/op_math/evolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"""
This submodule defines the Evolution class.
"""
import warnings
from warnings import warn

import numpy as np
Expand Down Expand Up @@ -74,7 +75,10 @@ class Evolution(Exp):
_name = "Evolution"
num_params = 1

def __init__(self, generator, param, do_queue=True, id=None):
def __init__(self, generator, param=1, do_queue=True, id=None):
warnings.warn(
"Please use `qml.evolve` to instantiate an `Evolution` operator.", UserWarning
)
super().__init__(generator, coeff=1j * param, do_queue=do_queue, id=id)
self._data = [param]

Expand Down
14 changes: 4 additions & 10 deletions pennylane/pulse/parametrized_evolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ class ParametrizedEvolution(Operation):
perform intermediate steps if necessary. It is recommended to just provide a start and end time.
Note that such absolute times only have meaning within an instance of
``ParametrizedEvolution`` and will not affect other gates.
time (str, optional): The name of the time-based parameter in the parametrized Hamiltonian.
Defaults to "t".
do_queue (bool): determines if the scalar product operator will be queued. Default is True.
id (str or None): id for the scalar product operator. Default is None.
Expand All @@ -78,11 +76,9 @@ class ParametrizedEvolution(Operation):
.. warning::
The time argument ``t`` corresponds to the time window used to compute the scalar-valued
functions present in the :class:`ParametrizedHamiltonian` class. Consequently, executing
two ``ParametrizedEvolution`` gates using the same time window does not mean both gates
are executed simultaneously, but rather both gates evaluate their respective scalar-valued
functions using the same time window.
Executing two ``ParametrizedEvolution`` gates using the same time values does not mean both
gates are executed simultaneously, but rather both gates evaluate their respective
scalar-valued functions using the same time values.
.. note::
Expand Down Expand Up @@ -158,13 +154,12 @@ class ParametrizedEvolution(Operation):
_name = "ParametrizedEvolution"
num_wires = AnyWires

# pylint: disable=too-many-arguments, super-init-not-called
# pylint: disable=too-many-arguments
def __init__(
self,
H: ParametrizedHamiltonian,
params: list = None,
t: Union[float, List[float]] = None,
time="t",
do_queue=True,
id=None,
**odeint_kwargs
Expand All @@ -178,7 +173,6 @@ def __init__(
"All operators inside the parametrized hamiltonian must have a matrix defined."
)
self.H = H
self.time = time
self.params = params
self.odeint_kwargs = odeint_kwargs
if t is None:
Expand Down
13 changes: 10 additions & 3 deletions tests/ops/functions/test_evolve.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
"""Unit tests for the ``evolve`` function."""
import warnings

import pytest

import pennylane as qml
Expand All @@ -23,6 +25,12 @@
class TestEvolveConstructor:
"""Unit tests for the evolve function"""

def test_evolve_doesnt_raise_any_warning(self):
"""Test that using `qml.evolve`, the warning inside `Evolution.__init__` is not raised."""
with warnings.catch_warnings():
warnings.simplefilter("error")
qml.evolve(qml.PauliX(0))

def test_evolve_returns_evolution_op(self):
"""Test that the evolve function returns the `Evolution` operator when the input is
a generic operator."""
Expand All @@ -32,9 +40,8 @@ def test_evolve_returns_evolution_op(self):

def test_matrix(self):
"""Test that the matrix of the evolved function is correct."""
op = qml.s_prod(2, qml.PauliX(0))
final_op = qml.evolve(op)
mat = qml.math.expm(1j * qml.matrix(op))
final_op = qml.evolve(qml.PauliX(0), coeff=2)
mat = qml.math.expm(-1j * qml.matrix(2 * qml.PauliX(0)))
assert qml.math.allequal(qml.matrix(final_op), mat)

def test_evolve_returns_parametrized_evolution(self):
Expand Down
4 changes: 4 additions & 0 deletions tests/ops/op_math/test_evolution.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,3 +161,7 @@ def test_generator_error_if_not_hermitian(self):
qml.QuantumFunctionError, match="of operation Evolution is not hermitian"
):
qml.generator(op)

def test_warning_is_raised(self):
with pytest.warns(UserWarning, match="Please use `qml.evolve"):
Evolution(qml.PauliX(0))

0 comments on commit 0995dc9

Please sign in to comment.