Skip to content

Commit

Permalink
Add InfoBox to QuantumTape and Update typehints (#6114)
Browse files Browse the repository at this point in the history
**Context:**
Differences between `QuantumTape` and `QuantumScript` need to be
emphasized more explicitly in the docs due to significant performance
differences.

**Description of the Change:**
- Added a `Note` box to the `QuantumTape` page, instructing users to use
`QuantumScript` if performance is a concern.
- Added `QuantumScriptBatch` as a counterpart to `QuantumTapeBatch`
- Updated relevant typehints to use `QuantumScript` and
`QuantumScriptBatch` instead.

**Benefits:**
- Better UX.

**Possible Drawbacks:**
- More confusion (?)

[[sc-22442](https://app.shortcut.com/xanaduai/story/22442)]
  • Loading branch information
Shiro-Raven authored Aug 22, 2024
1 parent 3646d80 commit d8ccd4a
Show file tree
Hide file tree
Showing 83 changed files with 423 additions and 428 deletions.
4 changes: 3 additions & 1 deletion doc/code/qml_tape.rst
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ TensorFlow, and PyTorch.
details on creating QNodes, as well as the :func:`~pennylane.qnode` decorator
and :func:`~pennylane.QNode` constructor.

.. _tape-vs-script:

QuantumTape versus QuantumScript
--------------------------------

Expand Down Expand Up @@ -66,6 +68,6 @@ and a reduction in unintended side effects, ``QuantumScript`` is strictly used i

.. automodapi:: pennylane.tape
:no-main-docstr:
:skip: QuantumTapeBatch, QuantumScriptBatch
:include-all-objects:
:skip: QuantumTapeBatch
:inheritance-diagram:
4 changes: 2 additions & 2 deletions pennylane/debugging/snapshot.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
from functools import partial

import pennylane as qml
from pennylane.tape import QuantumTape, QuantumTapeBatch
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.transforms import transform
from pennylane.typing import PostprocessingFn

Expand Down Expand Up @@ -56,7 +56,7 @@ def __exit__(self, exc_type, exc_value, exc_traceback):


@transform
def snapshots(tape: QuantumTape) -> tuple[QuantumTapeBatch, PostprocessingFn]:
def snapshots(tape: QuantumScript) -> tuple[QuantumScriptBatch, PostprocessingFn]:
r"""This transform processes :class:`~pennylane.Snapshot` instances contained in a circuit,
depending on the compatibility of the execution device.
For supported devices, the snapshots' measurements are computed as the execution progresses.
Expand Down
4 changes: 2 additions & 2 deletions pennylane/devices/_legacy_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@
from pennylane.operation import Observable, Operation, Operator, StatePrepBase, Tensor
from pennylane.ops import Hamiltonian, LinearCombination, Prod, SProd, Sum
from pennylane.queuing import QueuingManager
from pennylane.tape import QuantumScript, QuantumTape, expand_tape_state_prep
from pennylane.tape import QuantumScript, expand_tape_state_prep
from pennylane.wires import WireError, Wires


Expand Down Expand Up @@ -720,7 +720,7 @@ def expand_fn(self, circuit, max_expansion=10):

return self.default_expand_fn(circuit, max_expansion=max_expansion)

def batch_transform(self, circuit: QuantumTape):
def batch_transform(self, circuit: QuantumScript):
"""Apply a differentiable batch transform for preprocessing a circuit
prior to execution. This method is called directly by the QNode, and
should be overwritten if the device requires a transform that
Expand Down
12 changes: 6 additions & 6 deletions pennylane/devices/_qubit_device.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@
)
from pennylane.operation import Operation, operation_derivative
from pennylane.resource import Resources
from pennylane.tape import QuantumTape
from pennylane.tape import QuantumScript
from pennylane.wires import Wires

from ._legacy_device import Device
Expand Down Expand Up @@ -360,7 +360,7 @@ def execute(self, circuit, **kwargs):

return results

def shot_vec_statistics(self, circuit: QuantumTape):
def shot_vec_statistics(self, circuit: QuantumScript):
"""Process measurement results from circuit execution using a device
with a shot vector and return statistics.
Expand Down Expand Up @@ -438,7 +438,7 @@ def shot_vec_statistics(self, circuit: QuantumTape):

return tuple(results)

def _multi_meas_with_counts_shot_vec(self, circuit: QuantumTape, shot_tuple, r):
def _multi_meas_with_counts_shot_vec(self, circuit: QuantumScript, shot_tuple, r):
"""Auxiliary function of the shot_vec_statistics and execute
functions for post-processing the results of multiple measurements at
least one of which was a counts measurement.
Expand Down Expand Up @@ -611,7 +611,7 @@ def _measure(
)

def statistics(
self, circuit: QuantumTape, shot_range=None, bin_size=None
self, circuit: QuantumScript, shot_range=None, bin_size=None
): # pylint: disable=too-many-statements
"""Process measurement results from circuit execution and return statistics.
Expand Down Expand Up @@ -1623,7 +1623,7 @@ def sample(self, observable, shot_range=None, bin_size=None, counts=False):
)

def adjoint_jacobian(
self, tape: QuantumTape, starting_state=None, use_device_state=False
self, tape: QuantumScript, starting_state=None, use_device_state=False
): # pylint: disable=too-many-statements
"""Implements the adjoint method outlined in
`Jones and Gacon <https://arxiv.org/abs/2009.02823>`__ to differentiate an input tape.
Expand Down Expand Up @@ -1778,7 +1778,7 @@ def _adjoint_jacobian_processing(jac):
# must be 2-dimensional
return tuple(tuple(np.array(j_) for j_ in j) for j in jac)

def _get_diagonalizing_gates(self, circuit: QuantumTape) -> list[Operation]:
def _get_diagonalizing_gates(self, circuit: QuantumScript) -> list[Operation]:
"""Returns the gates that diagonalize the measured wires such that they
are in the eigenbasis of the circuit observables.
Expand Down
4 changes: 2 additions & 2 deletions pennylane/devices/default_clifford.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
VnEntropyMP,
)
from pennylane.ops.qubit.observables import BasisStateProjector
from pennylane.tape import QuantumTape, QuantumTapeBatch
from pennylane.tape import QuantumScript, QuantumScriptBatch
from pennylane.transforms import convert_to_numpy_parameters
from pennylane.transforms.core import TransformProgram
from pennylane.typing import Result, ResultBatch
Expand Down Expand Up @@ -497,7 +497,7 @@ def preprocess(

def execute(
self,
circuits: Union[QuantumTape, QuantumTapeBatch],
circuits: Union[QuantumScript, QuantumScriptBatch],
execution_config: ExecutionConfig = DefaultExecutionConfig,
) -> Union[Result, ResultBatch]:
max_workers = execution_config.device_options.get("max_workers", self._max_workers)
Expand Down
28 changes: 13 additions & 15 deletions pennylane/devices/default_qubit.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
from pennylane.logging import debug_logger, debug_logger_init
from pennylane.measurements.mid_measure import MidMeasureMP
from pennylane.ops.op_math.condition import Conditional
from pennylane.tape import QuantumTape, QuantumTapeBatch
from pennylane.tape import QuantumScript, QuantumScriptBatch, QuantumScriptOrBatch
from pennylane.transforms import convert_to_numpy_parameters
from pennylane.transforms.core import TransformProgram
from pennylane.typing import PostprocessingFn, Result, ResultBatch
Expand All @@ -53,8 +53,6 @@
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())

QuantumTape_or_Batch = Union[QuantumTape, QuantumTapeBatch]


def stopping_condition(op: qml.operation.Operator) -> bool:
"""Specify whether or not an Operator object is supported by the device."""
Expand Down Expand Up @@ -166,8 +164,8 @@ def all_state_postprocessing(results, measurements, wire_order):

@qml.transform
def adjoint_state_measurements(
tape: QuantumTape, device_vjp=False
) -> tuple[QuantumTapeBatch, PostprocessingFn]:
tape: QuantumScript, device_vjp=False
) -> tuple[QuantumScriptBatch, PostprocessingFn]:
"""Perform adjoint measurement preprocessing.
* Allows a tape with only expectation values through unmodified
Expand Down Expand Up @@ -483,7 +481,7 @@ def __init__(
def supports_derivatives(
self,
execution_config: Optional[ExecutionConfig] = None,
circuit: Optional[QuantumTape] = None,
circuit: Optional[QuantumScript] = None,
) -> bool:
"""Check whether or not derivatives are available for a given configuration and circuit.
Expand Down Expand Up @@ -614,7 +612,7 @@ def _setup_execution_config(self, execution_config: ExecutionConfig) -> Executio
@debug_logger
def execute(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
) -> Union[Result, ResultBatch]:
self.reset_prng_key()
Expand Down Expand Up @@ -669,7 +667,7 @@ def execute(
@debug_logger
def compute_derivatives(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
max_workers = execution_config.device_options.get("max_workers", self._max_workers)
Expand All @@ -689,7 +687,7 @@ def compute_derivatives(
@debug_logger
def execute_and_compute_derivatives(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
self.reset_prng_key()
Expand All @@ -713,7 +711,7 @@ def execute_and_compute_derivatives(
def supports_jvp(
self,
execution_config: Optional[ExecutionConfig] = None,
circuit: Optional[QuantumTape] = None,
circuit: Optional[QuantumScript] = None,
) -> bool:
"""Whether or not this device defines a custom jacobian vector product.
Expand All @@ -732,7 +730,7 @@ def supports_jvp(
@debug_logger
def compute_jvp(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
tangents: tuple[Number, ...],
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
Expand All @@ -752,7 +750,7 @@ def compute_jvp(
@debug_logger
def execute_and_compute_jvp(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
tangents: tuple[Number, ...],
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
Expand Down Expand Up @@ -781,7 +779,7 @@ def execute_and_compute_jvp(
def supports_vjp(
self,
execution_config: Optional[ExecutionConfig] = None,
circuit: Optional[QuantumTape] = None,
circuit: Optional[QuantumScript] = None,
) -> bool:
"""Whether or not this device defines a custom vector jacobian product.
Expand All @@ -800,7 +798,7 @@ def supports_vjp(
@debug_logger
def compute_vjp(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
cotangents: tuple[Number, ...],
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
Expand Down Expand Up @@ -868,7 +866,7 @@ def _state(circuit):
@debug_logger
def execute_and_compute_vjp(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
cotangents: tuple[Number, ...],
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
Expand Down
2 changes: 1 addition & 1 deletion pennylane/devices/default_qubit_legacy.py
Original file line number Diff line number Diff line change
Expand Up @@ -1099,7 +1099,7 @@ def classical_shadow(self, obs, circuit):

return self._cast(self._stack([outcomes, recipes]), dtype=np.int8)

def _get_diagonalizing_gates(self, circuit: qml.tape.QuantumTape) -> list[Operation]:
def _get_diagonalizing_gates(self, circuit: qml.tape.QuantumScript) -> list[Operation]:
meas_filtered = [
m
for m in circuit.measurements
Expand Down
11 changes: 4 additions & 7 deletions pennylane/devices/default_qutrit_mixed.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import pennylane as qml
from pennylane.logging import debug_logger, debug_logger_init
from pennylane.ops import _qutrit__channel__ops__ as channels
from pennylane.tape import QuantumTape, QuantumTapeBatch
from pennylane.tape import QuantumScript, QuantumScriptOrBatch
from pennylane.transforms.core import TransformProgram
from pennylane.typing import Result, ResultBatch

Expand All @@ -46,9 +46,6 @@
logger = logging.getLogger(__name__)
logger.addHandler(logging.NullHandler())

Result_or_ResultBatch = Union[Result, ResultBatch]
QuantumTape_or_Batch = Union[QuantumTape, QuantumTapeBatch]


observables = {
"THermitian",
Expand Down Expand Up @@ -293,7 +290,7 @@ def __init__( # pylint: disable=too-many-arguments
def supports_derivatives(
self,
execution_config: Optional[ExecutionConfig] = None,
circuit: Optional[QuantumTape] = None,
circuit: Optional[QuantumScript] = None,
) -> bool:
"""Check whether or not derivatives are available for a given configuration and circuit.
Expand Down Expand Up @@ -388,9 +385,9 @@ def preprocess(
@debug_logger
def execute(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
) -> Result_or_ResultBatch:
) -> Union[Result, ResultBatch]:
interface = (
execution_config.interface
if execution_config.gradient_method in {"best", "backprop", None}
Expand Down
16 changes: 7 additions & 9 deletions pennylane/devices/default_tensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,12 @@
)
from pennylane.operation import Observable, Operation, Tensor
from pennylane.ops import LinearCombination, Prod, SProd, Sum
from pennylane.tape import QuantumScript, QuantumTape, QuantumTapeBatch
from pennylane.tape import QuantumScript, QuantumScriptOrBatch
from pennylane.templates.subroutines.trotter import _recursive_expression
from pennylane.transforms.core import TransformProgram
from pennylane.typing import Result, ResultBatch, TensorLike
from pennylane.wires import WireError

QuantumTape_or_Batch = Union[QuantumTape, QuantumTapeBatch]

has_quimb = True

warnings.filterwarnings("ignore", message=".*kahypar")
Expand Down Expand Up @@ -624,7 +622,7 @@ def preprocess(

def execute(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
) -> Union[Result, ResultBatch]:
"""Execute a circuit or a batch of circuits and turn it into results.
Expand Down Expand Up @@ -829,7 +827,7 @@ def supports_derivatives(

def compute_derivatives(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
"""Calculate the Jacobian of either a single or a batch of circuits on the device.
Expand All @@ -847,7 +845,7 @@ def compute_derivatives(

def execute_and_compute_derivatives(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
"""Compute the results and Jacobians of circuits at the same time.
Expand All @@ -867,7 +865,7 @@ def execute_and_compute_derivatives(
def supports_vjp(
self,
execution_config: Optional[ExecutionConfig] = None,
circuit: Optional[QuantumTape] = None,
circuit: Optional[QuantumScript] = None,
) -> bool:
"""Whether or not this device defines a custom vector-Jacobian product.
Expand All @@ -882,7 +880,7 @@ def supports_vjp(

def compute_vjp(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
cotangents: tuple[Number, ...],
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
Expand All @@ -904,7 +902,7 @@ def compute_vjp(

def execute_and_compute_vjp(
self,
circuits: QuantumTape_or_Batch,
circuits: QuantumScriptOrBatch,
cotangents: tuple[Number, ...],
execution_config: ExecutionConfig = DefaultExecutionConfig,
):
Expand Down
Loading

0 comments on commit d8ccd4a

Please sign in to comment.