Source code for pennylane.devices.modifiers.single_tape_support
# Copyright 2018-2024 Xanadu Quantum Technologies Inc.# Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at# http://www.apache.org/licenses/LICENSE-2.0# Unless required by applicable law or agreed to in writing, software# distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions and# limitations under the License."""Defines the ``single_tape_support`` device modifier."""fromfunctoolsimportwrapsfrompennylane.devicesimportDefaultExecutionConfig,Devicefrompennylane.tapeimportQuantumScriptdef_make_execute(batch_execute):"""Allows an ``execute`` function to handle individual circuits."""@wraps(batch_execute)defexecute(self,circuits,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=(circuits,)results=batch_execute(self,circuits,execution_config)returnresults[0]ifis_single_circuitelseresultsreturnexecutedef_make_compute_derivatives(batch_derivatives):"""Allows an ``compute_derivatives`` method to handle individual circuits."""@wraps(batch_derivatives)defcompute_derivatives(self,circuits,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=(circuits,)jacs=batch_derivatives(self,circuits,execution_config)returnjacs[0]ifis_single_circuitelsejacsreturncompute_derivativesdef_make_execute_and_compute_derivatives(batch_execute_and_compute_derivatives):"""Allows an ``execute_and_compute_derivatives`` method to handle individual circuits."""@wraps(batch_execute_and_compute_derivatives)defexecute_and_compute_derivatives(self,circuits,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=(circuits,)results,jacs=batch_execute_and_compute_derivatives(self,circuits,execution_config)return(results[0],jacs[0])ifis_single_circuitelse(results,jacs)returnexecute_and_compute_derivativesdef_make_compute_jvp(batch_compute_jvp):"""Allows an ``compute_jvp`` method to handle individual circuits."""@wraps(batch_compute_jvp)defcompute_jvp(self,circuits,tangents,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=[circuits]tangents=[tangents]res=batch_compute_jvp(self,circuits,tangents,execution_config)returnres[0]ifis_single_circuitelseresreturncompute_jvpdef_make_execute_and_compute_jvp(batch_execute_and_compute_jvp):"""Allows an ``execute_and_compute_jvp`` method to handle individual circuits."""@wraps(batch_execute_and_compute_jvp)defexecute_and_compute_jvp(self,circuits,tangents,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=[circuits]tangents=[tangents]results,jvps=batch_execute_and_compute_jvp(self,circuits,tangents,execution_config)return(results[0],jvps[0])ifis_single_circuitelse(results,jvps)returnexecute_and_compute_jvpdef_make_compute_vjp(batch_compute_vjp):"""Allows an ``execute_and_compute_vjp`` method to handle individual circuits."""@wraps(batch_compute_vjp)defcompute_vjp(self,circuits,cotangents,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=[circuits]cotangents=[cotangents]res=batch_compute_vjp(self,circuits,cotangents,execution_config)returnres[0]ifis_single_circuitelseresreturncompute_vjpdef_make_execute_and_compute_vjp(batch_execute_and_compute_vjp):"""Allows an ``execute_and_compute_vjp`` method to handle individual circuits."""@wraps(batch_execute_and_compute_vjp)defexecute_and_compute_vjp(self,circuits,cotangents,execution_config=DefaultExecutionConfig):is_single_circuit=Falseifisinstance(circuits,QuantumScript):is_single_circuit=Truecircuits=[circuits]cotangents=[cotangents]results,vjps=batch_execute_and_compute_vjp(self,circuits,cotangents,execution_config)return(results[0],vjps[0])ifis_single_circuitelse(results,vjps)returnexecute_and_compute_vjp# pylint: disable=protected-access
[docs]defsingle_tape_support(cls:type)->type:"""Modifies all functions to accept single tapes in addition to batches. This allows the definition of the device class to purely focus on executing batches. Args: cls (type): a subclass of :class:`pennylane.devices.Device` Returns type: The inputted class that has now been modified to accept single circuits as well as batches. .. code-block:: python @single_tape_support class MyDevice(qml.devices.Device): def execute(self, circuits, execution_config = qml.devices.DefaultExecutionConfig): return tuple(0.0 for _ in circuits) >>> dev = MyDevice() >>> t = qml.tape.QuantumScript() >>> dev.execute(t) 0.0 >>> dev.execute((t, )) (0.0,) In this situation, ``MyDevice.execute`` only needs to handle the case where ``circuits`` is an iterable of :class:`~pennylane.tape.QuantumTape` objects, not a single value. """ifnotissubclass(cls,Device):raiseValueError("single_tape_support only accepts subclasses of pennylane.devices.Device")ifhasattr(cls,"_applied_modifiers"):cls._applied_modifiers.append(single_tape_support)else:cls._applied_modifiers=[single_tape_support]# execute must be definedcls.execute=_make_execute(cls.execute)modifier_map={"compute_derivatives":_make_compute_derivatives,"execute_and_compute_derivatives":_make_execute_and_compute_derivatives,"compute_jvp":_make_compute_jvp,"execute_and_compute_jvp":_make_execute_and_compute_jvp,"compute_vjp":_make_compute_vjp,"execute_and_compute_vjp":_make_execute_and_compute_vjp,}forname,modifierinmodifier_map.items():ifgetattr(cls,name)!=getattr(Device,name):original=getattr(cls,name)setattr(cls,name,modifier(original))returncls