Skip to content

Commit

Permalink
Daily rc sync to master (#5953)
Browse files Browse the repository at this point in the history
Automatic sync from the release candidate to master during a feature
freeze.

---------

Co-authored-by: Jay Soni <jbsoni@uwaterloo.ca>
Co-authored-by: Astral Cai <astral.cai@xanadu.ai>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: Yushao Chen (Jerry) <chenys13@outlook.com>
Co-authored-by: Christina Lee <chrissie.c.l@gmail.com>
Co-authored-by: Mudit Pandey <mudit.pandey@xanadu.ai>
Co-authored-by: Thomas R. Bromley <49409390+trbromley@users.noreply.github.com>
Co-authored-by: soranjh <40344468+soranjh@users.noreply.github.com>
Co-authored-by: Pietropaolo Frisoni <pietropaolo.frisoni@xanadu.ai>
Co-authored-by: Isaac De Vlugt <34751083+isaacdevlugt@users.noreply.github.com>
Co-authored-by: GitHub Actions Bot <>
  • Loading branch information
10 people authored Jul 5, 2024
1 parent 31412ab commit b7c25d4
Show file tree
Hide file tree
Showing 28 changed files with 159 additions and 113 deletions.
2 changes: 1 addition & 1 deletion doc/development/guide/installation.rst
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ importing PennyLane in Python.
requires ``pip install -e .`` to be re-run in the plugin repository
for the changes to take effect.

Apart from the core packages needed to run PennyLane. Some extra packages need
Apart from the core packages needed to run PennyLane, some extra packages need
to be installed for several development processes, such as linting, testing, and
pre-commit quality checks. Those can be installed easily via ``pip``:

Expand Down
7 changes: 5 additions & 2 deletions doc/releases/changelog-0.37.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,7 @@
[(#5654)](https://github.com/PennyLaneAI/pennylane/pull/5654)

* `qml.transforms.convert_to_numpy_parameters` is now a proper transform and its output signature has changed,
returning a list of `QuantumTape`s and a post-processing function instead of simply the transformed circuit.
returning a list of `QuantumScript`s and a post-processing function instead of simply the transformed circuit.
[(#5693)](https://github.com/PennyLaneAI/pennylane/pull/5693)

* `Controlled.wires` does not include `self.work_wires` anymore. That can be accessed separately through `Controlled.work_wires`.
Expand All @@ -452,6 +452,9 @@

<h3>Documentation 📝</h3>

* Several links to other functions in measurement process docstrings have been fixed.
[(#5913)](https://github.com/PennyLaneAI/pennylane/pull/5913)

* Move information about mid-circuit measurements from the measurements quickstart page to its own
[mid-circuit measurements quickstart page](https://docs.pennylane.ai/en/stable/introduction/mid_circuit_measurements.html)
[(#5870)](https://github.com/PennyLaneAI/pennylane/pull/5870)
Expand Down Expand Up @@ -509,7 +512,7 @@
* An error is now raised if a transform is applied to a catalyst qjit object.
[(#5826)](https://github.com/PennyLaneAI/pennylane/pull/5826)

* `KerasLayer` and `TorchLayer` no longer mutate the input `QNode`'s interface.
* `qml.qnn.KerasLayer` and `qml.qnn.TorchLayer` no longer mutate the input `qml.QNode`'s interface.
[(#5800)](https://github.com/PennyLaneAI/pennylane/pull/5800)

* Disable Docker builds on PR merge.
Expand Down
2 changes: 2 additions & 0 deletions pennylane/capture/capture_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ class CaptureMeta(type):
.. code-block::
qml.capture.enable()
class AbstractMyObj(jax.core.AbstractValue):
pass
Expand Down
29 changes: 16 additions & 13 deletions pennylane/capture/capture_qnode.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ def qnode_call(qnode: "qml.QNode", *args, **kwargs) -> "qml.typing.Result":
args: the arguments the QNode is called with
Keyword Args:
Any keyword arguments accepted by the quantum function
kwargs (Any): Any keyword arguments accepted by the quantum function
Returns:
qml.typing.Result: the result of a qnode execution
Expand All @@ -103,14 +103,16 @@ def qnode_call(qnode: "qml.QNode", *args, **kwargs) -> "qml.typing.Result":
.. code-block:: python
qml.capture.enable()
@qml.qnode(qml.device('lightning.qubit', wires=1))
def circuit(x):
qml.RX(x, wires=0)
return qml.expval(qml.Z(0)), qml.probs()
def f(x):
expval_z, probs = circuit(np.pi * x, shots=50)
return 2*expval_z + probs
expval_z, probs = circuit(np.pi * x, shots=50000)
return 2 * expval_z + probs
jaxpr = jax.make_jaxpr(f)(0.1)
print("jaxpr:")
Expand All @@ -128,22 +130,23 @@ def f(x):
{ lambda ; a:f32[]. let
b:f32[] = mul 3.141592653589793 a
c:f32[] d:f32[2] = qnode[
device=<lightning.qubit device (wires=1) at 0x107639010>
qfunc_jaxpr={ lambda ; e:f32[]. let
_:AbstractOperator() = RX[n_wires=1] e 0
f:AbstractOperator() = PauliZ[n_wires=1] 0
g:AbstractMeasurement(n_wires=None) = expval_obs f
h:AbstractMeasurement(n_wires=0) = probs_wires
device=<lightning.qubit device (wires=1) at 0x10557a070>
qfunc_jaxpr={ lambda ; e:f32[]. let
_:AbstractOperator() = RX[n_wires=1] e 0
f:AbstractOperator() = PauliZ[n_wires=1] 0
g:AbstractMeasurement(n_wires=None) = expval_obs f
h:AbstractMeasurement(n_wires=0) = probs_wires
in (g, h) }
qnode_kwargs={'diff_method': 'best', 'grad_on_execution': 'best', 'cache': False, 'cachesize': 10000, 'max_diff': 1, 'max_expansion': 10, 'device_vjp': False}
shots=Shots(total=50)
qnode=<QNode: device='<lightning.qubit device (wires=1) at 0x10557a070>', interface='auto', diff_method='best'>
qnode_kwargs={'diff_method': 'best', 'grad_on_execution': 'best', 'cache': False, 'cachesize': 10000, 'max_diff': 1, 'max_expansion': 10, 'device_vjp': False, 'mcm_method': None, 'postselect_mode': None}
shots=Shots(total=50000)
] b
i:f32[] = mul 2.0 c
j:f32[2] = add i d
in (j,) }
in (j,) }
result:
[Array([-1.3 , -0.74], dtype=float32)]
[Array([-0.96939224, -0.38207346], dtype=float32)]
"""
Expand Down
2 changes: 1 addition & 1 deletion pennylane/capture/explanations.md
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ Great!👍

Now you can see that the problem is that we lied in our definition of abstract evaluation. Jax thinks that `PrimitiveClass` returns something of shape `(1,)` and type `float32`.

But jax doesn't have an abstract type that really describes "PrimitiveClass". So we need to define an register our own.
But jax doesn't have an abstract type that really describes "PrimitiveClass". So we need to define and register our own.


```python
Expand Down
32 changes: 21 additions & 11 deletions pennylane/debugging/snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -123,12 +123,15 @@ def circuit():
{0: array([0.70710678+0.j, 0. +0.j, 0.70710678+0.j, 0. +0.j]),
'execution_results': {'00': 101, '11': 99}}
Here one can see how a device that does not natively support snapshots executes two different circuits:
Here one can see how a device that does not natively support snapshots executes two different circuits. Additionally, a warning
is raised along with the results:
.. code-block:: python3
dev = qml.device("lightning.qubit", shots=100, wires=2)
@qml.snapshots
@qml.qnode(qml.device("lightning.qubit", shots=100, wires=2), diff_method="parameter-shift")
@qml.qnode(dev)
def circuit():
qml.Hadamard(wires=0),
qml.Snapshot(qml.counts())
Expand All @@ -139,10 +142,18 @@ def circuit():
out = circuit()
>>> circuit.device.tracker.totals
{'batches': 1, 'simulations': 2, 'executions': 2, 'results': 0.0}
UserWarning: Snapshots are not supported for the given device. Therefore, a tape will be created for each snapshot, resulting in a total of n_snapshots + 1 executions.
warnings.warn(
{'batches': 1,
'simulations': 2,
'executions': 2,
'shots': 200,
'results': -0.16}
>>> out
{0: {'00': tensor(51, requires_grad=True), '10': tensor(49, requires_grad=True)}, 'execution_results': tensor(0., requires_grad=True)}
{0: {'00': tensor(52, requires_grad=True),
'10': tensor(48, requires_grad=True)},
'execution_results': tensor(-0.1, requires_grad=True)}
Here you can see the default behaviour of the transform for unsupported devices and you can see how the amount of wires included
in each resulting tape is minimal:
Expand Down Expand Up @@ -194,13 +205,6 @@ def circuit():
def postprocessing_fn(results, snapshot_tags):
return dict(zip(snapshot_tags, results))

if len(new_tapes) > 1:
warnings.warn(
"Snapshots are not supported for the given device. Therefore, a tape will be "
f"created for each snapshot, resulting in a total of {len(new_tapes)} executions.",
UserWarning,
)

return new_tapes, partial(postprocessing_fn, snapshot_tags=snapshot_tags)


Expand Down Expand Up @@ -240,4 +244,10 @@ def get_snapshots(*args, **kwargs):
if _is_snapshot_compatible(qnode.device):
return get_snapshots

warnings.warn(
"Snapshots are not supported for the given device. Therefore, a tape will be "
"created for each snapshot, resulting in a total of n_snapshots + 1 executions.",
UserWarning,
)

return self.default_qnode_transform(qnode, targs, tkwargs)
2 changes: 2 additions & 0 deletions pennylane/devices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
MCMConfig
Device
DefaultQubit
DefaultTensor
NullQubit
DefaultQutritMixed
Expand Down Expand Up @@ -160,6 +161,7 @@ def execute(self, circuits, execution_config = qml.devices.DefaultExecutionConfi
from .default_gaussian import DefaultGaussian
from .default_mixed import DefaultMixed
from .default_clifford import DefaultClifford
from .default_tensor import DefaultTensor
from .null_qubit import NullQubit
from .default_qutrit_mixed import DefaultQutritMixed
from .._device import Device as LegacyDevice
3 changes: 3 additions & 0 deletions pennylane/devices/default_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@
PostprocessingFn = Callable[[ResultBatch], Result_or_ResultBatch]

has_quimb = True

warnings.filterwarnings("ignore", message=".*kahypar")

try:
import quimb.tensor as qtn
except (ModuleNotFoundError, ImportError) as import_error: # pragma: no cover
Expand Down
44 changes: 23 additions & 21 deletions pennylane/devices/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ def validate_adjoint_trainable_params(

@transform
def decompose(
tape: qml.tape.QuantumTape,
tape: qml.tape.QuantumScript,
stopping_condition: Callable[[qml.operation.Operator], bool],
stopping_condition_shots: Callable[[qml.operation.Operator], bool] = None,
skip_initial_state_prep: bool = True,
Expand All @@ -274,34 +274,36 @@ def decompose(
"""Decompose operations until the stopping condition is met.
Args:
tape (QuantumTape or QNode or Callable): a quantum circuit.
stopping_condition (Callable): a function from an operator to a boolean. If ``False``, the operator
should be decomposed. If an operator cannot be decomposed and is not accepted by ``stopping_condition``,
an ``Exception`` will be raised (of a type specified by the ``error`` kwarg).
tape (QuantumScript or QNode or Callable): a quantum circuit.
stopping_condition (Callable): a function from an operator to a boolean. If ``False``,
the operator should be decomposed. If an operator cannot be decomposed and is not
accepted by ``stopping_condition``, an ``Exception`` will be raised (of a type
specified by the ``error`` keyward argument).
Keyword Args:
stopping_condition_shots (Callable): a function from an operator to a boolean. If ``False``, the operator
should be decomposed. If an operator cannot be decomposed and is not accepted by ``stopping_condition``,
an ``Exception`` will be raised (of a type specified by the ``error`` kwarg). This replaces stopping_condition if and only if the tape has shots.
skip_initial_state_prep (bool): If ``True``, the first operator will not be decomposed if it inherits
from :class:`~.StatePrepBase`. Defaults to ``True``.
decomposer (Callable): an optional callable that takes an operator and implements the relevant decomposition.
If None, defaults to using a callable returning ``op.decomposition()`` for any :class:`~.Operator` .
stopping_condition_shots (Callable): a function from an operator to a boolean. If
``False``, the operator should be decomposed. This replaces ``stopping_condition``
if and only if the tape has shots.
skip_initial_state_prep (bool): If ``True``, the first operator will not be decomposed if
it inherits from :class:`~.StatePrepBase`. Defaults to ``True``.
decomposer (Callable): an optional callable that takes an operator and implements the
relevant decomposition. If ``None``, defaults to using a callable returning
``op.decomposition()`` for any :class:`~.Operator` .
max_expansion (int): The maximum depth of the expansion. Defaults to None.
name (str): The name of the transform, process or device using decompose. Used in the error message. Defaults to "device".
error (Error): An error type to raise if it is not possible to obtain a decomposition that fulfills
the ``stopping_condition``. Defaults to ``DeviceError``.
name (str): The name of the transform, process or device using decompose. Used in the
error message. Defaults to "device".
error (type): An error type to raise if it is not possible to obtain a decomposition that
fulfills the ``stopping_condition``. Defaults to ``DeviceError``.
Returns:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumTape], function]:
qnode (QNode) or quantum function (Callable) or tuple[List[QuantumScript], function]:
The decomposed circuit. The output type is explained in :func:`qml.transform <pennylane.transform>`.
Raises:
Exception: Type defaults to ``DeviceError`` but can be modified via keyword argument. Raised if
an operator is not accepted and does not define a decomposition, or if the decomposition
enters an infinite loop and raises a ``RecursionError``.
Exception: Type defaults to ``DeviceError`` but can be modified via keyword argument.
Raised if an operator is not accepted and does not define a decomposition, or if
the decomposition enters an infinite loop and raises a ``RecursionError``.
**Example:**
Expand All @@ -320,7 +322,7 @@ def decompose(
>>> decompose(tape, lambda obj: obj.name == "S")
DeviceError: Operator CNOT(wires=[0, 1]) not supported on device and does not provide a decomposition.
The ``skip_initial_state_prep`` specifies whether or not the device supports state prep operations
The ``skip_initial_state_prep`` specifies whether the device supports state prep operations
at the beginning of the circuit.
>>> tape = qml.tape.QuantumScript([qml.BasisState([1], wires=0), qml.BasisState([1], wires=1)])
Expand Down
10 changes: 8 additions & 2 deletions pennylane/io.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ def from_qasm(quantum_circuit: str, measurements=False):
'measure q -> c;'
dev = qml.device("default.qubit")
loaded_circuit = qml.from_qasm(hadamard_qasm)
loaded_circuit = qml.from_qasm(hadamard_qasm, measurements=None)
@qml.qnode(dev)
def circuit():
Expand Down Expand Up @@ -503,7 +503,13 @@ def circuit():
function: the PennyLane template created based on the QASM string
"""
plugin_converter = plugin_converters["qasm"].load()
try:
plugin_converter = plugin_converters["qasm"].load()
except Exception as e: # pragma: no cover
raise RuntimeError( # pragma: no cover
"Failed to load the qasm plugin. Please ensure that the pennylane-qiskit package is installed."
) from e

if measurements is False:
measurements = []
if "measure" in quantum_circuit:
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/classical_shadow.py
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ class ClassicalShadowMP(MeasurementTransform):
"""Represents a classical shadow measurement process occurring at the end of a
quantum variational circuit.
Please refer to :func:`classical_shadow` for detailed documentation.
Please refer to :func:`pennylane.classical_shadow` for detailed documentation.
Args:
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/counts.py
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ class CountsMP(SampleMeasurement):
"""Measurement process that samples from the supplied observable and returns the number of
counts for each sample.
Please refer to :func:`counts` for detailed documentation.
Please refer to :func:`pennylane.counts` for detailed documentation.
Args:
obs (Union[.Operator, .MeasurementValue]): The observable that is to be measured
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/expval.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ def circuit(x):
class ExpectationMP(SampleMeasurement, StateMeasurement):
"""Measurement process that computes the expectation value of the supplied observable.
Please refer to :func:`expval` for detailed documentation.
Please refer to :func:`pennylane.expval` for detailed documentation.
Args:
obs (Union[.Operator, .MeasurementValue]): The observable that is to be measured
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/mid_measure.py
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ class MidMeasureMP(MeasurementProcess):
This class additionally stores information about unknown measurement outcomes in the qubit model.
Measurements on a single qubit in the computational basis are assumed.
Please refer to :func:`measure` for detailed documentation.
Please refer to :func:`pennylane.measure` for detailed documentation.
Args:
wires (.Wires): The wires the measurement process applies to.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/mutual_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ def circuit_mutual(x):
class MutualInfoMP(StateMeasurement):
"""Measurement process that computes the mutual information between the provided wires.
Please refer to :func:`mutual_info` for detailed documentation.
Please refer to :func:`pennylane.mutual_info` for detailed documentation.
Args:
wires (Sequence[.Wires]): The wires the measurement process applies to.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/probs.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ def circuit():
class ProbabilityMP(SampleMeasurement, StateMeasurement):
"""Measurement process that computes the probability of each computational basis state.
Please refer to :func:`probs` for detailed documentation.
Please refer to :func:`pennylane.probs` for detailed documentation.
Args:
obs (Union[.Operator, .MeasurementValue]): The observable that is to be measured
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/purity.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def circuit_purity(p):
class PurityMP(StateMeasurement):
"""Measurement process that computes the purity of the system prior to measurement.
Please refer to :func:`purity` for detailed documentation.
Please refer to :func:`pennylane.purity` for detailed documentation.
Args:
wires (.Wires): The wires the measurement process applies to.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/sample.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@ class SampleMP(SampleMeasurement):
"""Measurement process that returns the samples of a given observable. If no observable is
provided then basis state samples are returned directly from the device.
Please refer to :func:`sample` for detailed documentation.
Please refer to :func:`pennylane.sample` for detailed documentation.
Args:
obs (Union[.Operator, .MeasurementValue]): The observable that is to be measured
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def circuit():
class StateMP(StateMeasurement):
"""Measurement process that returns the quantum state in the computational basis.
Please refer to :func:`state` for detailed documentation.
Please refer to :func:`pennylane.state` for detailed documentation.
Args:
wires (.Wires): The wires the measurement process applies to.
Expand Down
2 changes: 1 addition & 1 deletion pennylane/measurements/var.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ def circuit(x):
class VarianceMP(SampleMeasurement, StateMeasurement):
"""Measurement process that computes the variance of the supplied observable.
Please refer to :func:`var` for detailed documentation.
Please refer to :func:`pennylane.var` for detailed documentation.
Args:
obs (Union[.Operator, .MeasurementValue]): The observable that is to be measured
Expand Down
Loading

0 comments on commit b7c25d4

Please sign in to comment.