Skip to content

Commit

Permalink
Daily rc sync to master (PennyLaneAI#4997)
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: Christina Lee <[email protected]>
Co-authored-by: Pieter Eendebak <[email protected]>
Co-authored-by: Christina Lee <[email protected]>
Co-authored-by: lillian542 <[email protected]>
Co-authored-by: lillian542 <[email protected]>
Co-authored-by: Tom Bromley <[email protected]>
Co-authored-by: Isaac De Vlugt <[email protected]>
Co-authored-by: Josh Izaac <[email protected]>
Co-authored-by: Matthew Silverman <[email protected]>
Co-authored-by: GitHub Actions Bot <>
  • Loading branch information
10 people committed Jan 5, 2024
1 parent f6a7375 commit ad63375
Show file tree
Hide file tree
Showing 23 changed files with 166 additions and 114 deletions.
8 changes: 4 additions & 4 deletions .github/workflows/interface-unit-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ on:
Indicate if a lightened version of the CI should be run instead of the entire suite.
The lightened version of the CI includes the following changes:
- Only Python 3.9 is tested against, instead of 3.9, 3.10, 3.11
- Only Python 3.9 is tested against, instead of 3.9, 3.10, 3.11, 3.12
required: false
type: boolean
default: false
Expand Down Expand Up @@ -70,10 +70,10 @@ jobs:
else
cat >python_versions.json <<-EOF
{
"default": ["3.9", "3.10", "3.11"],
"default": ["3.9", "3.10", "3.11", "3.12"],
"torch-tests": ["3.9", "3.11"],
"tf-tests": ["3.9", "3.10"],
"jax-tests": ["3.9", "3.11"],
"tf-tests": ["3.9", "3.11"],
"jax-tests": ["3.9", "3.12"],
"all-interfaces-tests": ["3.9"],
"external-libraries-tests": ["3.9"],
"qcut-tests": ["3.9"],
Expand Down
6 changes: 3 additions & 3 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ deprecations are listed below.
Pending deprecations
--------------------

* `qml.transforms.one_qubit_decomposition` and `qml.transforms.two_qubit_decomposition` are deprecated. Instead,
you should use `qml.ops.one_qubit_decomposition` and `qml.ops.two_qubit_decomposition` .
* ``qml.transforms.one_qubit_decomposition`` and ``qml.transforms.two_qubit_decomposition`` are deprecated. Instead,
you should use ``qml.ops.one_qubit_decomposition`` and ``qml.ops.two_qubit_decomposition`` .

- Deprecated in v0.34
- Will be removed in v0.35

* `Observable.return_type` is deprecated. Instead, you should inspect the type
* ``Observable.return_type`` is deprecated. Instead, you should inspect the type
of the surrounding measurement process.

- Deprecated in v0.34
Expand Down
6 changes: 3 additions & 3 deletions doc/introduction/inspecting_circuits.rst
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ During normal execution, the snapshots are ignored:
@qml.qnode(dev, interface=None)
def circuit():
qml.Snapshot(measurement=qml.expval(qml.PauliZ(0))
qml.Snapshot(measurement=qml.expval(qml.PauliZ(0)))
qml.Hadamard(wires=0)
qml.Snapshot("very_important_state")
qml.CNOT(wires=[0, 1])
Expand All @@ -149,8 +149,8 @@ results.

>>> qml.snapshots(circuit)()
{0: 1.0,
'very_important_state': array([0.70710678, 0., 0.70710678, 0.]),
2: array([0.70710678, 0., 0., 0.70710678]),
'very_important_state': array([0.707+0.j, 0.+0.j, 0.707+0.j, 0.+0.j]),
2: array([0.707+0.j, 0.+0.j, 0.+0.j, 0.707+0.j]),
'execution_results': 0.0}

Graph representation
Expand Down
20 changes: 17 additions & 3 deletions doc/releases/changelog-0.34.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -368,8 +368,6 @@
* The function ``qml.draw_mpl`` now accept a keyword argument ``fig`` to specify the output figure window.
[(#4956)](https://github.com/PennyLaneAI/pennylane/pull/4956)

<h4>Better support for batching</h4>

* `qml.AmplitudeEmbedding` now supports batching when used with Tensorflow.
[(#4818)](https://github.com/PennyLaneAI/pennylane/pull/4818)

Expand Down Expand Up @@ -444,6 +442,9 @@

<h4>Other improvements</h4>

* PennyLane now supports Python 3.12.
[(#4985)](https://github.com/PennyLaneAI/pennylane/pull/4985)

* `SampleMeasurement` now has an optional method `process_counts` for computing the measurement results from a counts
dictionary.
[(#4941)](https://github.com/PennyLaneAI/pennylane/pull/4941/)
Expand Down Expand Up @@ -606,6 +607,10 @@

<h3>Bug fixes 🐛</h3>

* `TransformDispatcher` now stops queuing when performing the transform when applying it to a qfunc.
Only the output of the transform will be queued.
[(#4983)](https://github.com/PennyLaneAI/pennylane/pull/4983)

* `qml.map_wires` now works properly with `qml.cond` and `qml.measure`.
[(#4884)](https://github.com/PennyLaneAI/pennylane/pull/4884)

Expand Down Expand Up @@ -668,6 +673,9 @@
wire order.
[(#4781)](https://github.com/PennyLaneAI/pennylane/pull/4781)

* `qml.compile` will now always decompose to `expand_depth`, even if a target basis set is not specified.
[(#4800)](https://github.com/PennyLaneAI/pennylane/pull/4800)

* `qml.transforms.transpile` can now handle measurements that are broadcasted onto all wires.
[(#4793)](https://github.com/PennyLaneAI/pennylane/pull/4793)

Expand Down Expand Up @@ -704,8 +712,14 @@
[(#4951)](https://github.com/PennyLaneAI/pennylane/pull/4951)

* `MPLDrawer` does not add the bonus space for classical wires when no classical wires are present.
[(#5987)](https://github.com/PennyLaneAI/pennylane/pull/4987)
[(#4987)](https://github.com/PennyLaneAI/pennylane/pull/4987)

* `Projector` now works with parameter-broadcasting.
[(#4993)](https://github.com/PennyLaneAI/pennylane/pull/4993)

* The jax-jit interface can now be used with float32 mode.
[(#4990)](https://github.com/PennyLaneAI/pennylane/pull/4990)

<h3>Contributors ✍️</h3>

This release contains contributions from (in alphabetical order):
Expand Down
17 changes: 0 additions & 17 deletions pennylane/_qubit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,6 @@
VnEntropyMP,
Shots,
)
from pennylane.ops.qubit.observables import BasisStateProjector
from pennylane.resource import Resources
from pennylane.operation import operation_derivative, Operation
from pennylane.tape import QuantumTape
Expand Down Expand Up @@ -1307,14 +1306,6 @@ def marginal_prob(self, prob, wires=None):
return self._reshape(prob, flat_shape)

def expval(self, observable, shot_range=None, bin_size=None):
if isinstance(observable, BasisStateProjector):
# branch specifically to handle the basis state projector observable
idx = int("".join(str(i) for i in observable.parameters[0]), 2)
probs = self.probability(
wires=observable.wires, shot_range=shot_range, bin_size=bin_size
)
return probs[idx]

# exact expectation value
if self.shots is None:
try:
Expand Down Expand Up @@ -1343,14 +1334,6 @@ def expval(self, observable, shot_range=None, bin_size=None):
return np.squeeze(np.mean(samples, axis=axis))

def var(self, observable, shot_range=None, bin_size=None):
if isinstance(observable, BasisStateProjector):
# branch specifically to handle the basis state projector observable
idx = int("".join(str(i) for i in observable.parameters[0]), 2)
probs = self.probability(
wires=observable.wires, shot_range=shot_range, bin_size=bin_size
)
return probs[idx] - probs[idx] ** 2

# exact variance value
if self.shots is None:
try:
Expand Down
4 changes: 2 additions & 2 deletions pennylane/debugging.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,8 +81,8 @@ def circuit():
>>> qml.snapshots(circuit)()
{0: 1.0,
'very_important_state': array([0.70710678, 0. , 0.70710678, 0. ]),
2: array([0.70710678, 0. , 0. , 0.70710678]),
'very_important_state': array([0.70710678+0.j, 0. +0.j, 0.70710678+0.j, 0. +0.j]),
2: array([0.70710678+0.j, 0. +0.j, 0. +0.j, 0.70710678+0.j]),
'execution_results': 0.0}
"""

Expand Down
5 changes: 2 additions & 3 deletions pennylane/devices/default_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,8 @@ def adjoint_state_measurements(tape: QuantumTape) -> (Tuple[QuantumTape], Callab
params = tape.get_parameters()
complex_data = [qml.math.cast(p, complex) for p in params]
tape = tape.bind_new_parameters(complex_data, list(range(len(params))))
state_tape = qml.tape.QuantumScript(
tape.operations, [qml.measurements.StateMP(wires=tape.wires)]
)
new_mp = qml.measurements.StateMP(wires=tape.wires)
state_tape = qml.tape.QuantumScript(tape.operations, [new_mp])
return (state_tape,), partial(
all_state_postprocessing, measurements=tape.measurements, wire_order=tape.wires
)
Expand Down
3 changes: 2 additions & 1 deletion pennylane/devices/qubit/apply_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,8 @@ def apply_snapshot(op: qml.Snapshot, state, is_state_batched: bool = False, debu
if measurement:
snapshot = qml.devices.qubit.measure(measurement, state)
else:
snapshot = math.flatten(state)
flat_shape = (math.shape(state)[0], -1) if is_state_batched else (-1,)
snapshot = math.cast(math.reshape(state, flat_shape), complex)
if op.tag:
debugger.snapshots[op.tag] = snapshot
else:
Expand Down
29 changes: 19 additions & 10 deletions pennylane/interfaces/jax_jit.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@

from .jax import _NonPytreeWrapper

dtype = jnp.float64
Zero = jax.custom_derivatives.SymbolicZero


Expand All @@ -71,18 +70,28 @@ def _set_parameters_on_copy(tapes, params):
return tuple(t.bind_new_parameters(a, list(range(len(a)))) for t, a in zip(tapes, params))


def _jax_dtype(m_type):
if m_type == int:
return jnp.int64 if jax.config.jax_enable_x64 else jnp.int32
if m_type == float:
return jnp.float64 if jax.config.jax_enable_x64 else jnp.float32
if m_type == complex:
return jnp.complex128 if jax.config.jax_enable_x64 else jnp.complex64
return jnp.dtype(m_type)


def _result_shape_dtype_struct(tape: "qml.tape.QuantumScript", device: "qml.Device"):
"""Auxiliary function for creating the shape and dtype object structure
given a tape."""

shape = tape.shape(device)
if len(tape.measurements) == 1:
tape_dtype = jnp.dtype(tape.numeric_type)
m_dtype = _jax_dtype(tape.measurements[0].numeric_type)
if tape.shots.has_partitioned_shots:
return tuple(jax.ShapeDtypeStruct(s, tape_dtype) for s in shape)
return jax.ShapeDtypeStruct(tuple(shape), tape_dtype)
return tuple(jax.ShapeDtypeStruct(s, m_dtype) for s in shape)
return jax.ShapeDtypeStruct(tuple(shape), m_dtype)

tape_dtype = tuple(jnp.dtype(elem) for elem in tape.numeric_type)
tape_dtype = tuple(_jax_dtype(m.numeric_type) for m in tape.measurements)
if tape.shots.has_partitioned_shots:
return tuple(
tuple(jax.ShapeDtypeStruct(tuple(s), d) for s, d in zip(si, tape_dtype)) for si in shape
Expand Down Expand Up @@ -129,7 +138,7 @@ def _execute_wrapper(params, tapes, execute_fn, _, device) -> ResultBatch:

def pure_callback_wrapper(p):
new_tapes = _set_parameters_on_copy(tapes.vals, p)
res = tuple(execute_fn(new_tapes))
res = tuple(_to_jax(execute_fn(new_tapes)))
# When executed under `jax.vmap` the `result_shapes_dtypes` will contain
# the shape without the vmap dimensions, while the function here will be
# executed with objects containing the vmap dimensions. So res[i].ndim
Expand All @@ -143,7 +152,7 @@ def pure_callback_wrapper(p):
return jax.tree_map(lambda r, s: r.T if r.ndim > s.ndim else r, res, shape_dtype_structs)

out = jax.pure_callback(pure_callback_wrapper, shape_dtype_structs, params, vectorized=True)
return _to_jax(out)
return out


def _execute_and_compute_jvp(tapes, execute_fn, jpc, device, primals, tangents):
Expand All @@ -165,15 +174,15 @@ def _execute_and_compute_jvp(tapes, execute_fn, jpc, device, primals, tangents):

def wrapper(inner_params):
new_tapes = _set_parameters_on_copy(tapes.vals, inner_params)
return jpc.execute_and_compute_jacobian(new_tapes)
return _to_jax(jpc.execute_and_compute_jacobian(new_tapes))

res_struct = tuple(_result_shape_dtype_struct(t, device) for t in tapes.vals)
jac_struct = tuple(_jac_shape_dtype_struct(t, device) for t in tapes.vals)
results, jacobians = jax.pure_callback(wrapper, (res_struct, jac_struct), primals[0])

jvps = _compute_jvps(jacobians, tangents_trainable, tapes.vals)

return _to_jax(results), _to_jax(jvps)
return results, jvps


def _vjp_fwd(params, tapes, execute_fn, jpc, device):
Expand All @@ -186,7 +195,7 @@ def _vjp_bwd(tapes, execute_fn, jpc, device, params, dy):

def wrapper(inner_params, inner_dy):
new_tapes = _set_parameters_on_copy(tapes.vals, inner_params)
return tuple(jpc.compute_vjp(new_tapes, inner_dy))
return _to_jax(jpc.compute_vjp(new_tapes, inner_dy))

vjp_shape = _pytree_shape_dtype_struct(params)
return (jax.pure_callback(wrapper, vjp_shape, params, dy),)
Expand Down
19 changes: 0 additions & 19 deletions pennylane/measurements/expval.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@

import pennylane as qml
from pennylane.operation import Operator
from pennylane.ops.qubit.observables import BasisStateProjector
from pennylane.wires import Wires

from .measurements import Expectation, SampleMeasurement, StateMeasurement
Expand Down Expand Up @@ -107,15 +106,6 @@ def process_samples(
shot_range: Tuple[int] = None,
bin_size: int = None,
):
if isinstance(self.obs, BasisStateProjector):
# branch specifically to handle the basis state projector observable
idx = int("".join(str(i) for i in self.obs.parameters[0]), 2)
with qml.queuing.QueuingManager.stop_recording():
probs = qml.probs(wires=self.wires).process_samples(
samples=samples, wire_order=wire_order, shot_range=shot_range, bin_size=bin_size
)
return probs[idx]

# estimate the ev
op = self.mv if self.mv is not None else self.obs
with qml.queuing.QueuingManager.stop_recording():
Expand All @@ -130,15 +120,6 @@ def process_samples(
return qml.math.squeeze(qml.math.mean(samples, axis=axis))

def process_state(self, state: Sequence[complex], wire_order: Wires):
if isinstance(self.obs, BasisStateProjector):
# branch specifically to handle the basis state projector observable
idx = int("".join(str(i) for i in self.obs.parameters[0]), 2)
with qml.queuing.QueuingManager.stop_recording():
probs = qml.probs(wires=self.wires).process_state(
state=state, wire_order=wire_order
)
return probs[idx]

# This also covers statistics for mid-circuit measurements manipulated using
# arithmetic operators
eigvals = qml.math.asarray(self.eigvals(), dtype="float64")
Expand Down
7 changes: 7 additions & 0 deletions pennylane/measurements/shots.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ class Shots:
>>> shots.total_shots, shots.shot_vector
(1210, (ShotCopies(10 shots x 1), ShotCopies(100 shots x 4), ShotCopies(200 shots x 4)))
Example constructing a Shots instance by multiplying an existing one by an int or float:
>>> Shots(100) * 2
Shots(total_shots=200, shot_vector=(ShotCopies(200 shots x 1),))
>>> Shots([7, (100, 2)]) * 1.5
Shots(total_shots=310, shot_vector=(ShotCopies(10 shots x 1), ShotCopies(150 shots x 2)))
One should also note that specifying a single tuple of length 2 is considered two different
shot values, and *not* a tuple-pair representing shots and copies to avoid special behaviour
depending on the iterable type:
Expand Down
22 changes: 0 additions & 22 deletions pennylane/measurements/var.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@

import pennylane as qml
from pennylane.operation import Operator
from pennylane.ops.qubit.observables import BasisStateProjector
from pennylane.wires import Wires

from .measurements import SampleMeasurement, StateMeasurement, Variance
Expand Down Expand Up @@ -107,16 +106,6 @@ def process_samples(
shot_range: Tuple[int] = None,
bin_size: int = None,
):
if isinstance(self.obs, BasisStateProjector):
# branch specifically to handle the basis state projector observable
idx = int("".join(str(i) for i in self.obs.parameters[0]), 2)
# we use ``self.wires`` instead of ``self.obs`` because the observable was
# already applied before the sampling
probs = qml.probs(wires=self.wires).process_samples(
samples=samples, wire_order=wire_order, shot_range=shot_range, bin_size=bin_size
)
return probs[idx] - probs[idx] ** 2

# estimate the variance
op = self.mv if self.mv is not None else self.obs
with qml.queuing.QueuingManager.stop_recording():
Expand All @@ -131,17 +120,6 @@ def process_samples(
return qml.math.squeeze(qml.math.var(samples, axis=axis))

def process_state(self, state: Sequence[complex], wire_order: Wires):
if isinstance(self.obs, BasisStateProjector):
# branch specifically to handle the basis state projector observable
idx = int("".join(str(i) for i in self.obs.parameters[0]), 2)
# we use ``self.wires`` instead of ``self.obs`` because the observable was
# already applied to the state
with qml.queuing.QueuingManager.stop_recording():
probs = qml.probs(wires=self.wires).process_state(
state=state, wire_order=wire_order
)
return probs[idx] - probs[idx] ** 2

# This also covers statistics for mid-circuit measurements manipulated using
# arithmetic operators
eigvals = qml.math.asarray(self.eigvals(), dtype="float64")
Expand Down
Loading

0 comments on commit ad63375

Please sign in to comment.