Skip to content

Commit

Permalink
Remove output_dim property of qml.tape.QuantumScript (#6829)
Browse files Browse the repository at this point in the history
**Context:**
The property `output_dim` of `QuantumScript` has been deprecated in
previous round, [sc-74594]
#6577. Now we would love to
remove it entirely.

**Description of the Change:**
 - Remove property `output_dim` along with its tests, warnings, etc.
 - Remove the detached attribute `_output_dim` after previous removal.
- Remove the detached private method `_update_output_dim` which used to
be strictly only helping update property `output_dim`.

**Benefits:**
Cleaner codebase with less redundancies.

**Possible Drawbacks:**
Not known. Perhaps some nuances hidden in some uncovered cornercase
tests. Anyways potential drawback won't affect any current feature in
principle.

**Related GitHub Issues:**
[sc-82150]

---------

Co-authored-by: lillian542 <[email protected]>
  • Loading branch information
JerryChen97 and lillian542 authored Jan 15, 2025
1 parent 14c61a6 commit 3bec1cd
Show file tree
Hide file tree
Showing 6 changed files with 11 additions and 147 deletions.
10 changes: 5 additions & 5 deletions doc/development/deprecations.rst
Original file line number Diff line number Diff line change
Expand Up @@ -25,11 +25,6 @@ Pending deprecations
- Deprecated in v0.40
- Will be removed in v0.41

* The ``output_dim`` property of ``qml.tape.QuantumScript`` has been deprecated. Instead, use method ``shape`` of ``QuantumScript`` or ``MeasurementProcess`` to get the same information.

- Deprecated in v0.40
- Will be removed in v0.41

* The ``QNode.get_best_method`` and ``QNode.best_method_str`` methods have been deprecated.
Instead, use the ``qml.workflow.get_best_diff_method`` function.

Expand Down Expand Up @@ -84,6 +79,11 @@ for details on how to port your legacy code to the new system. The following fun
Completed deprecation cycles
----------------------------

* The ``output_dim`` property of ``qml.tape.QuantumScript`` has been removed. Instead, use method ``shape`` of ``QuantumScript`` or ``MeasurementProcess`` to get the same information.

- Deprecated in v0.40
- Removed in v0.41

* The ``qml.qsvt_legacy`` function has been removed.
Instead, use ``qml.qsvt``. The new functionality takes an input polynomial instead of angles.

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

<h3>Breaking changes 💔</h3>

* The `output_dim` property of `qml.tape.QuantumScript` has been removed. Instead, use method `shape` of `QuantumScript` or `MeasurementProcess` to get the same information.
[(#6829)](https://github.com/PennyLaneAI/pennylane/pull/6829)

* Removed method `qsvt_legacy` along with its private helper `_qsp_to_qsvt`
[(#6827)](https://github.com/PennyLaneAI/pennylane/pull/6827)

Expand Down
1 change: 0 additions & 1 deletion pennylane/devices/_legacy_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,6 @@ def _local_tape_expand(tape, depth, stop_at):

# Update circuit info
new_tape._batch_size = tape._batch_size
new_tape._output_dim = tape._output_dim
return new_tape


Expand Down
51 changes: 1 addition & 50 deletions pennylane/tape/qscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
from typing import Any, Optional, TypeVar, Union

import pennylane as qml
from pennylane.measurements import MeasurementProcess, ProbabilityMP, StateMP
from pennylane.measurements import MeasurementProcess
from pennylane.measurements.shots import Shots, ShotsLike
from pennylane.operation import _UNSET_BATCH_SIZE, Observable, Operation, Operator
from pennylane.pytrees import register_pytree
Expand Down Expand Up @@ -183,7 +183,6 @@ def __init__(
self._trainable_params = trainable_params
self._graph = None
self._specs = None
self._output_dim = None
self._batch_size = _UNSET_BATCH_SIZE

self._obs_sharing_wires = None
Expand Down Expand Up @@ -322,29 +321,6 @@ def batch_size(self) -> Optional[int]:
self._update_batch_size()
return self._batch_size

@property
def output_dim(self) -> int:
"""The (inferred) output dimension of the quantum script.
.. warning::
``QuantumScript.output_dim`` is being deprecated. Instead, considering
using method ``shape`` of ``QuantumScript`` or ``MeasurementProcess``
to get the same information. See ``qml.gradients.parameter_shift_cv.py::_get_output_dim``
for an example.
"""
# pylint: disable=import-outside-toplevel
import warnings

warnings.warn(
"The 'output_dim' property is deprecated and will be removed in version 0.41",
qml.PennyLaneDeprecationWarning,
)
if self._output_dim is None:
self._update_output_dim() # this will set _batch_size if it isn't already
return self._output_dim

@property
def diagonalizing_gates(self) -> list[Operation]:
"""Returns the gates that diagonalize the measured wires such that they
Expand Down Expand Up @@ -566,28 +542,6 @@ def _update_batch_size(self):

self._batch_size = candidate

def _update_output_dim(self):
"""Update the dimension of the output of the quantum script.
Sets:
self._output_dim (int): Size of the quantum script output (when flattened)
This method makes use of `self.batch_size`, so that `self._batch_size`
needs to be up to date when calling it.
Call `_update_batch_size` before `_update_output_dim`
"""
self._output_dim = 0
for m in self.measurements:
# attempt to infer the output dimension
if isinstance(m, ProbabilityMP):
# TODO: what if we had a CV device here? Having the base as
# 2 would have to be swapped to the cutoff value
self._output_dim += 2 ** len(m.wires)
elif not isinstance(m, StateMP):
self._output_dim += 1
if self.batch_size:
self._output_dim *= self.batch_size

# ========================================================
# Parameter handling
# ========================================================
Expand Down Expand Up @@ -984,9 +938,6 @@ def copy(self, copy_operations: bool = False, **update) -> "QuantumScript":
# obs may change if measurements were updated
new_qscript._obs_sharing_wires = self._obs_sharing_wires
new_qscript._obs_sharing_wires_id = self._obs_sharing_wires_id
if not (update.get("measurements") or update.get("operations")):
# output_dim may change if either measurements or operations were updated
new_qscript._output_dim = self._output_dim
return new_qscript

def __copy__(self) -> "QuantumScript":
Expand Down
2 changes: 0 additions & 2 deletions pennylane/tape/tape.py
Original file line number Diff line number Diff line change
Expand Up @@ -294,7 +294,6 @@ def stop_at(obj): # pylint: disable=unused-argument

# Update circuit info
new_tape._batch_size = tape._batch_size
new_tape._output_dim = tape._output_dim
return new_tape


Expand Down Expand Up @@ -343,7 +342,6 @@ def expand_tape_state_prep(tape, skip_first=True):

# Update circuit info
new_tape._batch_size = tape._batch_size
new_tape._output_dim = tape._output_dim
return new_tape


Expand Down
91 changes: 2 additions & 89 deletions tests/tape/test_qscript.py
Original file line number Diff line number Diff line change
Expand Up @@ -318,63 +318,21 @@ def test_error_inconsistent_batch_sizes(self, x, rot, y):
):
_ = tape.batch_size

@pytest.mark.parametrize(
"m, output_dim",
[
([qml.expval(qml.PauliX(0))], 1),
([qml.expval(qml.PauliX(0)), qml.var(qml.PauliY(1))], 2),
([qml.probs(wires=(0, 1))], 4),
([qml.state()], 0),
([qml.probs((0, 1)), qml.expval(qml.PauliX(0))], 5),
],
)
@pytest.mark.parametrize("ops, factor", [([], 1), ([qml.RX([1.2, 2.3, 3.4], wires=0)], 3)])
def test_update_output_dim(self, m, output_dim, ops, factor):
"""Test setting the output_dim property."""
qs = QuantumScript(ops, m)

with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert qs.output_dim == output_dim * factor

def test_lazy_batch_size_and_output_dim(self):
"""Test that batch_size and output_dim are computed lazily."""
def test_lazy_batch_size(self):
"""Test that batch_size is computed lazily."""
qs = QuantumScript([qml.RX([1.1, 2.2], 0)], [qml.expval(qml.PauliZ(0))])
copied = qs.copy()
assert qs._batch_size is _UNSET_BATCH_SIZE
assert qs._output_dim is None
# copying did not evaluate them either
assert copied._batch_size is _UNSET_BATCH_SIZE
assert copied._output_dim is None

# now evaluate it
assert qs.batch_size == 2
assert qs._output_dim is None # setting batch_size didn't set output_dim

with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert qs.output_dim == 2
copied = qs.copy()
assert qs._batch_size == 2
assert qs._output_dim == 2
# copied tape has it pre-evaluated
assert copied._batch_size == 2
assert copied._output_dim == 2

def test_lazy_setting_output_dim_sets_batch_size(self):
"""Test that setting the output_dim also sets the batch_size."""
qs = QuantumScript([qml.RX([1.1, 2.2], 0)], [qml.expval(qml.PauliZ(0))])
assert qs._batch_size is _UNSET_BATCH_SIZE
assert qs._output_dim is None

with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert qs.output_dim == 2 # getting this sets both _output_dim and _batch_size
assert qs._output_dim == 2
assert qs._batch_size == 2


class TestIteration:
Expand Down Expand Up @@ -583,12 +541,6 @@ def test_shallow_copy(self):
assert qs.data == copied_qs.data
assert qs.shots is copied_qs.shots

# check that the output dim is identical
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert qs.output_dim == copied_qs.output_dim

# pylint: disable=unnecessary-lambda
@pytest.mark.parametrize(
"copy_fn", [lambda tape: tape.copy(copy_operations=True), lambda tape: copy.copy(tape)]
Expand Down Expand Up @@ -621,12 +573,6 @@ def test_shallow_copy_with_operations(self, copy_fn):
assert qs.data == copied_qs.data
assert qs.shots is copied_qs.shots

# check that the output dim is identical
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert qs.output_dim == copied_qs.output_dim

def test_deep_copy(self):
"""Test that deep copying a tape works, and copies all constituent data except parameters"""
prep = [qml.BasisState(np.array([1, 0]), wires=(0, 1))]
Expand All @@ -644,12 +590,6 @@ def test_deep_copy(self):
assert all(m1 is not m2 for m1, m2 in zip(copied_qs.measurements, qs.measurements))
assert copied_qs.shots is qs.shots

# check that the output dim is identical
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert qs.output_dim == copied_qs.output_dim

# The underlying operation data has also been copied
assert copied_qs.operations[0].wires is not qs.operations[0].wires

Expand Down Expand Up @@ -763,10 +703,6 @@ def test_cached_properties_when_updating_operations(self):
tape = QuantumScript(ops, measurements=[qml.counts()], shots=2500, trainable_params=[1])

assert tape.batch_size == 2
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert tape.output_dim == 2
assert tape.trainable_params == [1]

new_ops = [qml.RX([1.2, 2.3, 3.4], 0)]
Expand All @@ -776,10 +712,6 @@ def test_cached_properties_when_updating_operations(self):
assert new_tape.operations == new_ops

assert new_tape.batch_size == 3
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert new_tape.output_dim == 3
assert new_tape.trainable_params == [0]

def test_cached_properties_when_updating_measurements(self):
Expand All @@ -797,10 +729,6 @@ def test_cached_properties_when_updating_measurements(self):

assert tape.obs_sharing_wires == []
assert tape.obs_sharing_wires_id == []
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert tape.output_dim == 2
assert tape.trainable_params == [1]

new_measurements = [qml.expval(qml.X(0)), qml.var(qml.Y(0))]
Expand All @@ -809,10 +737,6 @@ def test_cached_properties_when_updating_measurements(self):
assert tape.measurements == measurements
assert new_tape.measurements == new_measurements

with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
assert new_tape.output_dim == 4
assert new_tape.obs_sharing_wires == [qml.X(0), qml.Y(0)]
assert new_tape.obs_sharing_wires_id == [0, 1]
assert new_tape.trainable_params == [0, 1]
Expand Down Expand Up @@ -1734,14 +1658,3 @@ def test_jax_pytree_integration(qscript_type):
assert data[3] == 3.4
assert data[4] == 2.0
assert qml.math.allclose(data[5], eye_mat)


@pytest.mark.parametrize("qscript_type", (QuantumScript, qml.tape.QuantumTape))
@pytest.mark.parametrize("shots", [None, 1, 10])
def test_output_dim_is_deprecated(qscript_type, shots):
"""Test that the output_dim property is deprecated."""
with pytest.warns(
qml.PennyLaneDeprecationWarning, match="The 'output_dim' property is deprecated"
):
qscript = qscript_type([], [], shots=shots)
_ = qscript.output_dim

0 comments on commit 3bec1cd

Please sign in to comment.