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

Daily rc sync to master 2022-04-25 #2488

Merged
merged 21 commits into from
Apr 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
822da84
Remove deprecated `get_unitary_matrix` (#2457)
rmoyard Apr 19, 2022
82da18c
Rename `doc/releases/changelog-dev.md` → `doc/releases/changelog-0.23…
antalszava Apr 19, 2022
1bab718
Fix the issue with JAX JIT for grad when `diff_method="adjoint"` and …
maliasadi Apr 20, 2022
089bb29
Bugfix for Nesterov Momentum Optimier (#2466)
albi3ro Apr 20, 2022
8558ce9
Use pennylane numpy in molecular hamiltonian (#2465)
soranjh Apr 20, 2022
5e766cb
Remove `qml.finite_diff` (#2464)
albi3ro Apr 20, 2022
c14f88e
Update qchem documentation (#2454)
soranjh Apr 21, 2022
833dbfc
fix mera formatting issues (#2470)
albi3ro Apr 21, 2022
426efbb
Fix qcut doc render (#2471)
rmoyard Apr 21, 2022
30569d9
fix has_matrix (#2476)
albi3ro Apr 21, 2022
cfc608e
use qml.eigvals because MeasurementProcess.eigvals is being deprecate…
antalszava Apr 22, 2022
7950210
Warn upon import of an `ObservableReturnType` from operation instead …
albi3ro Apr 22, 2022
c0119b1
Update chemistry doc (#2482)
soranjh Apr 22, 2022
9c9764a
Automatic upload to pip when released (#2484)
rmoyard Apr 22, 2022
da3306f
Jacobian Slice Bug StrawberryFields (#2485)
puzzleshark Apr 22, 2022
4d27af9
Documentation fixes for the v0.23.0 release (#2472)
dime10 Apr 23, 2022
0b49215
Issue a warning about repeated cached executions with shot noise (#2478)
dime10 Apr 23, 2022
63ca6f0
exclude files from pr
Apr 25, 2022
582bb09
Exclude more files
dime10 Apr 25, 2022
4ffb52b
Merge branch 'master' into rc_2022-04-25-03-35-08
dime10 Apr 25, 2022
cb8e945
Merge branch 'master' into rc_2022-04-25-03-35-08
dime10 Apr 25, 2022
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
1 change: 1 addition & 0 deletions .github/workflows/upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ jobs:
pip install -r requirements-ci.txt
python setup.py bdist_wheel
pip install dist/PennyLane*.whl

- name: Run tests
run: |
python -m pytest pennylane/devices/tests \
Expand Down
2 changes: 1 addition & 1 deletion doc/code/qml_qchem.rst
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ The :func:`~.molecular_hamiltonian` function can be also used to construct the m
with a non-differentiable backend that uses the
`OpenFermion-PySCF <https://github.com/quantumlib/OpenFermion-PySCF>`_ plugin interfaced with the
electronic structure package `PySCF <https://github.com/sunqm/pyscf>`_. The non-differentiable
backend can be selected by setting `method='pyscf'` in :func:`~.molecular_hamiltonian`:
backend can be selected by setting ``method='pyscf'`` in :func:`~.molecular_hamiltonian`:

.. code-block:: python

Expand Down
7 changes: 4 additions & 3 deletions doc/introduction/chemistry.rst
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ contains a differentiable Hartree-Fock solver and the functionality to construct
fully-differentiable molecular Hamiltonian that can be used as input to quantum algorithms
such as the variational quantum eigensolver (VQE) algorithm. The :mod:`~.qchem` module
also provides tools for building other observables such as molecular dipole moment, spin
and particle number observables.
and particle number observables. The theoretical foundation of the quantum chemistry functionality
in PennyLane is explained in our `white paper <https://arxiv.org/abs/2111.09967>`_.

Building the electronic Hamiltonian
-----------------------------------
Expand Down Expand Up @@ -34,7 +35,7 @@ with an external backend that uses the
`OpenFermion-PySCF <https://github.com/quantumlib/OpenFermion-PySCF>`_ plugin interfaced with the
electronic structure package `PySCF <https://github.com/sunqm/pyscf>`_, which requires separate
installation. This backend is non-differentiable and can be selected by setting
`method='pyscf'` in :func:`~.molecular_hamiltonian`.
``method='pyscf'`` in :func:`~.molecular_hamiltonian`.

Furthermore, the net charge,
the `spin multiplicity <https://en.wikipedia.org/wiki/Multiplicity_(chemistry)>`_, the
Expand Down Expand Up @@ -73,7 +74,7 @@ where a quantum computer is used to prepare the trial wave function of a molecul
the expectation value of the *electronic Hamiltonian*, while a classical optimizer is used to
find its ground state.

PennyLane supports treating Hamiltonians just like any other observable, and the
PennyLane supports treating Hamiltonians just like any other observable, and the
expectation value of a Hamiltonian can be calculated using ``qml.expval``:

.. code-block:: python
Expand Down
4 changes: 2 additions & 2 deletions doc/introduction/measurements.rst
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ by a ``Hadamard`` and ``CNOT`` gate.
import pennylane as qml
from pennylane import numpy as np

dev = qml.device("default.qubit", wires=2)
dev = qml.device("default.qubit", wires=2, shots=1000)

@qml.qnode(dev)
def circuit():
Expand Down Expand Up @@ -130,7 +130,7 @@ Probability

You can also train QNodes on computational basis probabilities, by using
the :func:`~.pennylane.probs` measurement function. The function can
accept either specified ``wires`` or an observable that rotates the
accept either specified ``wires`` or an observable that rotates the
computational basis.

.. code-block:: python3
Expand Down
10 changes: 9 additions & 1 deletion pennylane/interfaces/autograd.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,15 @@ def grad_fn(dy):

vjps = [qml.gradients.compute_vjp(d, jac) for d, jac in zip(dy, jacs)]

return [qml.math.to_numpy(v, max_depth=_n) if isinstance(v, ArrayBox) else v for v in vjps]
return_vjps = [
qml.math.to_numpy(v, max_depth=_n) if isinstance(v, ArrayBox) else v for v in vjps
]
if device.capabilities().get("provides_jacobian", False):
# in the case where the device provides the jacobian,
# the output of grad_fn must be wrapped in a tuple in
# order to match the input parameters to _execute.
return (return_vjps,)
return return_vjps

return grad_fn

Expand Down
30 changes: 30 additions & 0 deletions pennylane/interfaces/execution.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@
# pylint: disable=import-outside-toplevel,too-many-arguments,too-many-branches,not-callable
from functools import wraps
import itertools
import warnings
import inspect
from contextlib import _GeneratorContextManager
from cachetools import LRUCache

import pennylane as qml
Expand Down Expand Up @@ -119,6 +122,33 @@ def wrapper(tapes, **kwargs):
if hashes[i] in cache:
# Tape exists within the cache, store the cached result
cached_results[i] = cache[hashes[i]]

# Introspect the set_shots decorator of the input function:
# warn the user in case of finite shots with cached results
finite_shots = False

closure = inspect.getclosurevars(fn).nonlocals
if "original_fn" in closure: # deal with expand_fn wrapper above
closure = inspect.getclosurevars(closure["original_fn"]).nonlocals

# retrieve the captured context manager instance (for set_shots)
if "self" in closure and isinstance(closure["self"], _GeneratorContextManager):
# retrieve the shots from the arguments or device instance
if closure["self"].func.__name__ == "set_shots":
dev, shots = closure["self"].args
shots = dev.shots if shots is False else shots
finite_shots = isinstance(shots, int)

if finite_shots:
warnings.warn(
"Cached execution with finite shots detected!\n"
"Note that samples as well as all noisy quantities computed via sampling "
"will be identical across executions. This situation arises where tapes "
"are executed with identical operations, measurements, and parameters.\n"
"To avoid this behavior, provide 'cache=False' to the QNode or execution "
"function.",
UserWarning,
)
else:
# Tape does not exist within the cache, store the tape
# for execution via the execution function.
Expand Down
9 changes: 5 additions & 4 deletions pennylane/measurements.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import numpy as np

import pennylane as qml
from pennylane.operation import Observable
from pennylane.wires import Wires

# =============================================================================
Expand Down Expand Up @@ -494,7 +493,7 @@ def circuit(x):
Raises:
QuantumFunctionError: `op` is not an instance of :class:`~.Observable`
"""
if not isinstance(op, (Observable, qml.Hamiltonian)):
if not isinstance(op, (qml.operation.Observable, qml.Hamiltonian)):
raise qml.QuantumFunctionError(
f"{op.name} is not an observable: cannot be used with expval"
)
Expand Down Expand Up @@ -529,7 +528,7 @@ def circuit(x):
Raises:
QuantumFunctionError: `op` is not an instance of :class:`~.Observable`
"""
if not isinstance(op, Observable):
if not isinstance(op, qml.operation.Observable):
raise qml.QuantumFunctionError(f"{op.name} is not an observable: cannot be used with var")

return MeasurementProcess(Variance, obs=op, shape=(1,), numeric_type=float)
Expand Down Expand Up @@ -607,7 +606,9 @@ def circuit(x):
case ``qml.sample(obs)`` is interpreted as a single-shot expectation value of the
observable ``obs``.
"""
if not isinstance(op, Observable) and op is not None: # None type is also allowed for op
if (
not isinstance(op, qml.operation.Observable) and op is not None
): # None type is also allowed for op
raise qml.QuantumFunctionError(
f"{op.name} is not an observable: cannot be used with sample"
)
Expand Down
14 changes: 14 additions & 0 deletions pennylane/operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,20 @@
from .utils import pauli_eigs


def __getattr__(name):
# for more information on overwriting `__getattr__`, see https://peps.python.org/pep-0562/
warning_names = {"Sample", "Variance", "Expectation", "Probability", "State", "MidMeasure"}
if name in warning_names:
obj = getattr(qml.measurements, name)
warning_string = f"qml.operation.{name} is deprecated. Please import from qml.measurements.{name} instead"
warnings.warn(warning_string, UserWarning)
return obj
try:
return globals()[name]
except KeyError as e:
raise AttributeError from e


def expand_matrix(base_matrix, wires, wire_order):
"""Re-express a base matrix acting on a subspace defined by a set of wire labels
according to a global wire order.
Expand Down
17 changes: 9 additions & 8 deletions pennylane/transforms/control.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,7 +188,8 @@ def ctrl(fn, control, control_values=None):
Args:
fn (function): Any python function that applies pennylane operations.
control (Wires): The control wire(s).
control_values (list[int]): The values the control wire(s) should take.
control_values (int or list[int]): The value(s) the control wire(s) should take.
Integers other than 0 or 1 will be treated as ``int(bool(x))``.

Returns:
function: A new function that applies the controlled equivalent of ``fn``. The returned
Expand Down Expand Up @@ -240,7 +241,7 @@ def my_circuit2():

.. Note::

Some devices are able to take advantage of the inherient sparsity of a
Some devices are able to take advantage of the inherent sparsity of a
controlled operation. In those cases, it may be more efficient to use
this transform rather than adding controls by hand. For devices that don't
have special control support, the operation is expanded to add control wires
Expand All @@ -255,25 +256,25 @@ def my_circuit2():
.. code-block:: python3

# These two ops are equivalent.
op1 = qml.ctrl(qml.ctrl(my_ops, 1), 2)
op2 = qml.ctrl(my_ops, [2, 1])
op1 = qml.ctrl(qml.ctrl(ops, 1), 2)
op2 = qml.ctrl(ops, [2, 1])

**Control Value Assignment**

Control values can be assigned as follows.

.. code-block:: python3

op = qml.ctrl(qml.ctrl(my_ops, 1), 2, control_values=0)
op()
op = qml.ctrl(ops, 2, control_values=0)
op(params=[0.1, 0.2])

This is equivalent to the following.

.. code-block:: python3

qml.PauliX(wires=2)
op = qml.ctrl(qml.ctrl(my_ops, 1), 2)
op()
op = qml.ctrl(ops, 2)
op(params=[0.1, 0.2])
qml.PauliX(wires=2)

"""
Expand Down
34 changes: 18 additions & 16 deletions pennylane/transforms/qcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -967,7 +967,7 @@ def cut_circuit_mc(
Args:
tape (QuantumTape): the tape of the full circuit to be cut
classical_processing_fn (callable): A classical postprocessing function to be applied to
the reconstructed bitstrings. The expected input is a bitstring; a flat array of length ``wires``.
the reconstructed bitstrings. The expected input is a bitstring; a flat array of length ``wires``,
and the output should be a single number within the interval :math:`[-1, 1]`.
If not supplied, the transform will output samples.
auto_cutter (Union[bool, Callable]): Toggle for enabling automatic cutting with the default
Expand Down Expand Up @@ -1093,6 +1093,8 @@ def circuit(x):

.. code-block:: python

np.random.seed(42)

with qml.tape.QuantumTape() as tape:
qml.Hadamard(wires=0)
qml.CNOT(wires=[0, 1])
Expand Down Expand Up @@ -1126,9 +1128,9 @@ def circuit(x):
qml.sample(wires=[0, 1, 2])

>>> cut_graph = qml.transforms.qcut.find_and_place_cuts(
graph=qml.transforms.qcut.tape_to_graph(uncut_tape),
cut_strategy=qml.transforms.qcut.CutStrategy(max_free_wires=2),
)
... graph=qml.transforms.qcut.tape_to_graph(uncut_tape),
... cut_strategy=qml.transforms.qcut.CutStrategy(max_free_wires=2),
... )
>>> print(qml.transforms.qcut.graph_to_tape(cut_graph).draw())
0: ──H─╭C───────────┤ Sample[|1⟩⟨1|]
1: ────╰X──//──X─╭C─┤ Sample[|1⟩⟨1|]
Expand Down Expand Up @@ -1187,11 +1189,11 @@ def circuit(x):

>>> shots = 3
>>> configurations, settings = qml.transforms.qcut.expand_fragment_tapes_mc(
... fragment_tapes, communication_graph, shots=shots
... )
... fragment_tapes, communication_graph, shots=shots
... )
>>> tapes = tuple(tape for c in configurations for tape in c)
>>> settings
tensor([[0, 4, 7]], requires_grad=True)
tensor([[6, 3, 4]], requires_grad=True)

Each configuration is drawn below:

Expand All @@ -1202,21 +1204,21 @@ def circuit(x):
.. code-block::

0: ──H─╭C────┤ Sample[|1⟩⟨1|]
1: ────╰X──X─┤ Sample[I]
1: ────╰X──X─┤ Sample[Z]

0: ──H─╭C────┤ Sample[|1⟩⟨1|]
1: ────╰X──X─┤ Sample[Y]
1: ────╰X──X─┤ Sample[X]

0: ──H─╭C────┤ Sample[|1⟩⟨1|]
1: ────╰X──X─┤ Sample[Z]
1: ────╰X──X─┤ Sample[Y]

0: ──I─╭C─┤ Sample[|1⟩⟨1|]
1: ────╰X─┤ Sample[|1⟩⟨1|]

0: ──H──S─╭C─┤ Sample[|1⟩⟨1|]
0: ──X──S─╭C─┤ Sample[|1⟩⟨1|]
1: ───────╰X─┤ Sample[|1⟩⟨1|]

0: ──X─╭C─┤ Sample[|1⟩⟨1|]
0: ──H─╭C─┤ Sample[|1⟩⟨1|]
1: ────╰X─┤ Sample[|1⟩⟨1|]

The last step is to execute the tapes and postprocess the results using
Expand All @@ -1229,9 +1231,9 @@ def circuit(x):
... communication_graph,
... shots=shots,
... )
[array([[1., 0., 0.],
[0., 0., 0.],
[1., 1., 1.]])]
[array([[0., 0., 0.],
[1., 0., 0.],
[1., 0., 0.]])]

Alternatively, it is possible to calculate an expectation value if a classical
processing function is provided that will accept the reconstructed circuit bitstrings
Expand All @@ -1252,7 +1254,7 @@ def fn(x):
... shots,
... fn
... )
array(4.)
array(-4.)
"""
# pylint: disable=unused-argument, too-many-arguments

Expand Down
28 changes: 28 additions & 0 deletions tests/interfaces/test_autograd.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from pennylane import numpy as np

import pennylane as qml
from pennylane.devices import DefaultQubit
from pennylane.gradients import finite_diff, param_shift
from pennylane.interfaces import execute

Expand Down Expand Up @@ -1111,3 +1112,30 @@ def test_multiple_hamiltonians_trainable(self, cost_fn, execute_kwargs, tol):
res = np.hstack(qml.jacobian(cost_fn)(weights, coeffs1, coeffs2, dev=dev))
expected = self.cost_fn_jacobian(weights, coeffs1, coeffs2)
assert np.allclose(res, expected, atol=tol, rtol=0)


class TestCustomJacobian:
def test_custom_jacobians(self):
class CustomJacobianDevice(DefaultQubit):
@classmethod
def capabilities(cls):
capabilities = super().capabilities()
capabilities["provides_jacobian"] = True
return capabilities

def jacobian(self, tape):
return np.array([1.0, 2.0, 3.0, 4.0])

dev = CustomJacobianDevice(wires=2)

@qml.qnode(dev, diff_method="device")
def circuit(v):
qml.RX(v, wires=0)
return qml.probs(wires=[0, 1])

d_circuit = qml.jacobian(circuit, argnum=0)

params = np.array(1.0, requires_grad=True)

d_out = d_circuit(params)
assert np.allclose(d_out, np.array([1.0, 2.0, 3.0, 4.0]))
10 changes: 10 additions & 0 deletions tests/test_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
# pylint: disable=no-self-use, no-member, protected-access, pointless-statement


@pytest.mark.parametrize(
"return_type", ("Sample", "Variance", "Expectation", "Probability", "State", "MidMeasure")
)
def test_obersvablereturntypes_import_warnings(return_type):
"""Test that accessing the observable return types through qml.operation emit a warning."""

with pytest.warns(UserWarning, match=r"is deprecated"):
getattr(qml.operation, return_type)


class TestOperatorConstruction:
"""Test custom operators construction."""

Expand Down
Loading