Skip to content

Commit

Permalink
Merge branch 'master' into update-python-version-to-3_8-in-install-page
Browse files Browse the repository at this point in the history
  • Loading branch information
rmoyard authored Jun 15, 2023
2 parents 6737e9d + ccf24c6 commit 493a08d
Show file tree
Hide file tree
Showing 82 changed files with 3,865 additions and 443 deletions.
12 changes: 12 additions & 0 deletions doc/_static/draw_mpl/draw_mpl_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,17 @@ def wires_labels(circuit):
plt.close()


def mid_measure():
def circuit():
m0 = qml.measure(0)
qml.Hadamard(1)
qml.cond(m0, qml.PauliZ)(1)

_ = draw_mpl(circuit)()
plt.savefig(folder / "mid_measure.png")
plt.close()


if __name__ == "__main__":

dev = qml.device("lightning.qubit", wires=(0, 1, 2, 3))
Expand All @@ -139,3 +150,4 @@ def circuit(x, z):
use_style(circuit)
rcparams(circuit)
wires_labels(circuit)
mid_measure()
Binary file added doc/_static/draw_mpl/mid_measure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added doc/_static/drawer/cond.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions doc/_static/drawer/mpldrawer_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,18 @@ def ctrl(savefile="ctrl.png"):
plt.close()


def cond(savefile="cond.png"):
drawer = MPLDrawer(n_wires=3, n_layers=4)

drawer.cond(layer=1, measured_layer=0, wires=[0], wires_target=[1])

options = {'color': "indigo", 'linewidth': 1.5}
drawer.cond(layer=3, measured_layer=2, wires=(1,), wires_target=(2,), options=options)

plt.savefig(folder / savefile)
plt.close()


def CNOT(savefile="cnot.png"):
drawer = MPLDrawer(n_wires=2, n_layers=2)

Expand Down Expand Up @@ -250,3 +262,4 @@ def float_layer(savefile="float_layer.png"):
integration(style="black_white", savefile="black_white_style.png")
integration_rcParams()
integration_formatted()
cond()
Binary file added doc/_static/tape_mpl/mid_measure.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions doc/_static/tape_mpl/tape_mpl_examples.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,18 @@ def postprocessing(tape):
plt.close()


def mid_measure():
with qml.queuing.AnnotatedQueue() as q:
m0 = qml.measure(0)
qml.Hadamard(1)
qml.cond(m0, qml.PauliZ)(1)

circuit = qml.tape.QuantumScript.from_queue(q)
_ = tape_mpl(circuit)
plt.savefig(folder / "mid_measure.png")
plt.close()


if __name__ == "__main__":

with qml.tape.QuantumTape() as tape:
Expand All @@ -144,3 +156,4 @@ def postprocessing(tape):
rcparams(tape)
wires_and_labels(tape)
postprocessing(tape)
mid_measure()
5 changes: 0 additions & 5 deletions doc/development/adding_operators.rst
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,6 @@ The basic components of operators are the following:
[0+0j, 0+0j, 9.95e-01-2.26e-18j 2.72e-17-9.98e-02j]
[0+0j, 0+0j, 2.72e-17-9.98e-02j 9.95e-01-2.26e-18j]]

.. note::

The :meth:`.Operator.matrix` method is temporary and will be renamed to :meth:`.Operator.matrix` in an
upcoming release. It is recommended to use the higher-level :func:`~.matrix` function where possible.

* Representation as a **sparse matrix** (:meth:`.Operator.sparse_matrix`):

>>> from scipy.sparse.coo import coo_matrix
Expand Down
35 changes: 32 additions & 3 deletions doc/releases/changelog-dev.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,13 @@
[(#4164)](https://github.com/PennyLaneAI/pennylane/pull/4164)

* Added the `FermiWord` class to represent a fermionic operator such as
$\hat{c}_1 c_0 \hat{c}_2 c_3$.
:math:`a^\dagger_1 a_0 a^\dagger_2 a_3`.
[(#4191)](https://github.com/PennyLaneAI/pennylane/pull/4191)

* Added a conversion function `jordan_wigner` that converts a fermionic operator (`FermiWord`) to a qubit
operator (`PauliSentence`) using the Jordan-Wigner mapping.
[(#4201)](https://github.com/PennyLaneAI/pennylane/pull/4201)

* Added the `FermiSentence` class to represent a linear combination of fermionic operators.
[(#4195)](https://github.com/PennyLaneAI/pennylane/pull/4195)

Expand All @@ -38,8 +42,10 @@
* Added the `QutritBasisState` operator to support qutrit state preparation for the `default.qutrit` device
[(#4185)](https://github.com/PennyLaneAI/pennylane/pull/4185)

* Added the `one_qubit_decomposition` function to provide a unified interface for all one qubit decompositions.
* Added the `one_qubit_decomposition` function to provide a unified interface for all one qubit decompositions. All
decompositions simplify the rotations angles to be between `0` and `4` pi.
[(#4210)](https://github.com/PennyLaneAI/pennylane/pull/4210)
[(#4246)](https://github.com/PennyLaneAI/pennylane/pull/4246)

<h3>Improvements 🛠</h3>

Expand Down Expand Up @@ -196,10 +202,24 @@
`qml.math.relative_entropy`, `qml.math.max_entropy`, and `qml.math.sqrt_matrix`.
[(#4186)](https://github.com/PennyLaneAI/pennylane/pull/4186)

* Added a transform dispatcher.
[(#4109)](https://github.com/PennyLaneAI/pennylane/pull/4109)

* Added a transform program.
[(#4187)](https://github.com/PennyLaneAI/pennylane/pull/4187)

* Added broadcasting support for `qml.qinfo.reduced_dm`, `qml.qinfo.purity`, `qml.qinfo.vn_entropy`,
`qml.qinfo.mutual_info`, `qml.qinfo.fidelity`, `qml.qinfo.relative_entropy`, and `qml.qinfo.trace_distance`.
[(#4234)](https://github.com/PennyLaneAI/pennylane/pull/4234)

* Fix unclear documentation and indicate variable-length argument lists of functions and methods in
the respective docstrings.
[(#4242)](https://github.com/PennyLaneAI/pennylane/pull/4242)

* Added the ability to draw mid-circuit measurements connected by classical control signals
to conditional operations.
[(#4228)](https://github.com/PennyLaneAI/pennylane/pull/4228)

<h4>Trace distance is now available in qml.qinfo 💥</h4>

* The quantum information module now supports computation of [trace distance](https://en.wikipedia.org/wiki/Trace_distance).
Expand Down Expand Up @@ -238,8 +258,14 @@
* The `qml.qnn.KerasLayer` and `qml.qnn.TorchLayer` classes now natively support parameter broadcasting.
[(#4131)](https://github.com/PennyLaneAI/pennylane/pull/4131)

* `qchem.import_operator()` will now return an arithmetic operator if `enable_new_opmath()` is active.
[(#4204)](https://github.com/PennyLaneAI/pennylane/pull/4204)

* Updated repr for ParametrizedHamiltonian.
[(##4176)](https://github.com/PennyLaneAI/pennylane/pull/4176)
[(#4176)](https://github.com/PennyLaneAI/pennylane/pull/4176)

* The new device interface is integrated with `qml.execute` for Tensorflow.
[(#4169)](https://github.com/PennyLaneAI/pennylane/pull/4169)

<h3>Breaking changes 💔</h3>

Expand Down Expand Up @@ -308,6 +334,9 @@

<h3>Bug fixes 🐛</h3>

* Fixes the matrix of `SProd` when the coefficient is tensorflow and the target matrix is not `complex128`.
[(#4249)](https://github.com/PennyLaneAI/pennylane/pull/4249)

* Fixes adjoint jacobian results with `grad_on_execution=False` in the JAX-JIT interface.
[(4217)](https://github.com/PennyLaneAI/pennylane/pull/4217)

Expand Down
92 changes: 16 additions & 76 deletions pennylane/_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
import abc
import types
import warnings
from collections import OrderedDict, namedtuple
from collections import OrderedDict
from collections.abc import Iterable, Sequence
from functools import lru_cache

Expand All @@ -43,69 +43,6 @@
from pennylane.tape import QuantumScript, QuantumTape
from pennylane.wires import WireError, Wires

ShotTuple = namedtuple("ShotTuple", ["shots", "copies"])
"""tuple[int, int]: Represents copies of a shot number."""


def _process_shot_sequence(shot_list):
"""Process the shot sequence, to determine the total
number of shots and the shot vector.
Args:
shot_list (Sequence[int, tuple[int]]): sequence of non-negative shot integers
Returns:
tuple[int, list[.ShotTuple[int]]]: A tuple containing the total number
of shots, as well as a list of shot tuples.
**Example**
>>> shot_list = [3, 1, 2, 2, 2, 2, 6, 1, 1, 5, 12, 10, 10]
>>> _process_shot_sequence(shot_list)
(57,
[ShotTuple(shots=3, copies=1),
ShotTuple(shots=1, copies=1),
ShotTuple(shots=2, copies=4),
ShotTuple(shots=6, copies=1),
ShotTuple(shots=1, copies=2),
ShotTuple(shots=5, copies=1),
ShotTuple(shots=12, copies=1),
ShotTuple(shots=10, copies=2)])
The total number of shots (57), and a sparse representation of the shot
sequence is returned, where tuples indicate the number of times a shot
integer is repeated.
"""
if all(isinstance(s, int) for s in shot_list):
if len(set(shot_list)) == 1:
# All shots are identical, only require a single shot tuple
shot_vector = [ShotTuple(shots=shot_list[0], copies=len(shot_list))]
else:
# Iterate through the shots, and group consecutive identical shots
split_at_repeated = np.split(shot_list, np.diff(shot_list).nonzero()[0] + 1)
shot_vector = [ShotTuple(shots=int(i[0]), copies=len(i)) for i in split_at_repeated]

elif all(isinstance(s, (int, tuple)) for s in shot_list):
# shot list contains tuples; assume it is already in a sparse representation
shot_vector = [
ShotTuple(*i) if isinstance(i, tuple) else ShotTuple(i, 1) for i in shot_list
]

else:
raise ValueError(f"Unknown shot sequence format {shot_list}")

total_shots = int(np.sum(np.prod(shot_vector, axis=1)))
return total_shots, shot_vector


def _get_num_copies(shot_vector):
"""Helper function to determine the number of copies from a shot vector Sequence(int) or Sequence(ShotTuple)."""
if any(isinstance(shot_comp, ShotTuple) for shot_comp in shot_vector):
len_shot_vec = sum(shot_v.copies for shot_v in shot_vector)
else:
len_shot_vec = len(shot_vector)
return len_shot_vec


class DeviceError(Exception):
"""Exception raised by a :class:`~.pennylane._device.Device` when it encounters an illegal
Expand Down Expand Up @@ -136,8 +73,10 @@ def __init__(self, wires=1, shots=1000, *, analytic=None):
self.shots = shots

if analytic is not None:
msg = "The analytic argument has been replaced by shots=None. "
msg += "Please use shots=None instead of analytic=True."
msg = (
"The analytic argument has been replaced by shots=None. "
"Please use shots=None instead of analytic=True."
)
raise DeviceError(msg)

if not isinstance(wires, Iterable):
Expand Down Expand Up @@ -275,7 +214,8 @@ def shots(self, shots):

elif isinstance(shots, Sequence) and not isinstance(shots, str):
# device is in batched sampling mode
self._shots, self._shot_vector = _process_shot_sequence(shots)
shot_obj = qml.measurements.Shots(shots)
self._shots, self._shot_vector = shot_obj.total_shots, list(shot_obj.shot_vector)
self._raw_shot_sequence = shots

else:
Expand All @@ -285,7 +225,7 @@ def shots(self, shots):

@property
def shot_vector(self):
"""list[.ShotTuple[int, int]]: Returns the shot vector, a sparse
"""list[~pennylane.measurements.ShotCopies]: Returns the shot vector, a sparse
representation of the shot sequence used by the device
when evaluating QNodes.
Expand All @@ -295,14 +235,14 @@ def shot_vector(self):
>>> dev.shots
57
>>> dev.shot_vector
[ShotTuple(shots=3, copies=1),
ShotTuple(shots=1, copies=1),
ShotTuple(shots=2, copies=4),
ShotTuple(shots=6, copies=1),
ShotTuple(shots=1, copies=2),
ShotTuple(shots=5, copies=1),
ShotTuple(shots=12, copies=1),
ShotTuple(shots=10, copies=2)]
[ShotCopies(3 shots x 1),
ShotCopies(1 shots x 1),
ShotCopies(2 shots x 4),
ShotCopies(6 shots x 1),
ShotCopies(1 shots x 2),
ShotCopies(5 shots x 1),
ShotCopies(12 shots x 1),
ShotCopies(10 shots x 2)]
The sparse representation of the shot
sequence is returned, where tuples indicate the number of times a shot
Expand Down
6 changes: 3 additions & 3 deletions pennylane/devices/qubit/initialize_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@

from typing import Iterable, Union

import numpy as np
import pennylane as qml
from pennylane import numpy as np


def create_initial_state(
wires: Union[qml.wires.Wires, Iterable],
prep_operation: qml.operation.StatePrep = None,
like: str = "numpy",
like: str = None,
):
r"""
Returns an initial state, defaulting to :math:`\ket{0}` if no state-prep operator is provided.
Expand All @@ -31,7 +31,7 @@ def create_initial_state(
wires (Union[Wires, Iterable]): The wires to be present in the initial state
prep_operation (Optional[StatePrep]): An operation to prepare the initial state
like (Optional[str]): The machine learning interface used to create the initial state.
Defaults to numpy
Defaults to None
Returns:
array: The initial state of a circuit
Expand Down
2 changes: 1 addition & 1 deletion pennylane/devices/qubit/preprocess.py
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ def validate_measurements(
execution_config (.ExecutionConfig): execution configuration with configurable
options for the execution.
"""
if circuit.shots.total_shots is None:
if not circuit.shots:
for m in circuit.measurements:
if not isinstance(m, StateMeasurement):
raise DeviceError(f"Analytic circuits must only contain StateMeasurements; got {m}")
Expand Down
2 changes: 1 addition & 1 deletion pennylane/devices/qubit/sampling.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@
# limitations under the License.
"""Functions to sample a state."""

import numpy as np
import pennylane as qml
from pennylane import numpy as np
from pennylane.ops import Sum, Hamiltonian
from pennylane.measurements import SampleMeasurement, Shots, ExpectationMP
from pennylane.typing import TensorLike
Expand Down
8 changes: 4 additions & 4 deletions pennylane/devices/qubit/simulate.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
# limitations under the License.
"""Simulate a quantum script."""
# pylint: disable=protected-access
import pennylane as qml
from numpy.random import default_rng

import pennylane.numpy as np
import pennylane as qml
from pennylane.typing import Result

from .initialize_state import create_initial_state
Expand Down Expand Up @@ -60,7 +60,7 @@ def simulate(circuit: qml.tape.QuantumScript, rng=None, debugger=None) -> Result
for op in circuit._ops:
state = apply_operation(op, state, debugger=debugger)

if circuit.shots.total_shots is None:
if not circuit.shots:
# analytic case

if len(circuit.measurements) == 1:
Expand All @@ -73,7 +73,7 @@ def simulate(circuit: qml.tape.QuantumScript, rng=None, debugger=None) -> Result
if len(circuit.measurements) == 1:
return measure_with_samples(circuit.measurements[0], state, shots=circuit.shots, rng=rng)

rng = np.random.default_rng(rng)
rng = default_rng(rng)
results = tuple(
measure_with_samples(mp, state, shots=circuit.shots, rng=rng) for mp in circuit.measurements
)
Expand Down
Loading

0 comments on commit 493a08d

Please sign in to comment.