# 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."""Stores classes and logic to define and track algorithmic error in a quantum workflow."""fromabcimportABC,abstractmethodimportpennylaneasqmlfrompennylane.operationimportOperation,Operator
[docs]classAlgorithmicError(ABC):"""Abstract base class representing an abstract type of error. This class can be used to create objects that track and propagate errors introduced by approximations and other algorithmic inaccuracies. Args: error (float): The numerical value of the error .. note:: Child classes must implement the :func:`~.AlgorithmicError.combine` method which combines two instances of this error type (as if the associated gates were applied in series). """def__init__(self,error:float):self.error=error
[docs]@abstractmethoddefcombine(self,other):"""A method to combine two errors of the same type. (e.g., additive, square additive, multiplicative, etc.) Args: other (AlgorithmicError): The other instance of error being combined. Returns: AlgorithmicError: The total error after combination. """
[docs]@staticmethoddefget_error(approximate_op,exact_op):"""A method to allow users to compute this type of error between two operators. Args: approximate_op (.Operator): The approximate operator. exact_op (.Operator): The exact operator. Returns: float: The error between the exact operator and its approximation. """raiseNotImplementedError
[docs]classErrorOperation(Operation):r"""Base class that represents quantum operations which carry some form of algorithmic error. .. note:: Child classes must implement the :func:`~.ErrorOperation.error` method which computes the error of the operation. """
[docs]@abstractmethoddeferror(self,*args,**kwargs)->AlgorithmicError:"""Computes the error of the operation. Returns: AlgorithmicError: The error. """
[docs]classSpectralNormError(AlgorithmicError):"""Class representing the spectral norm error. The spectral norm error is defined as the distance, in spectral norm, between the true unitary we intend to apply and the approximate unitary that is actually applied. Args: error (float): The numerical value of the error **Example** >>> s1 = SpectralNormError(0.01) >>> s2 = SpectralNormError(0.02) >>> s1.combine(s2) SpectralNormError(0.03) """def__repr__(self):"""Return formal string representation."""returnf"SpectralNormError({self.error})"
[docs]defcombine(self,other:"SpectralNormError"):"""Combine two spectral norm errors. Args: other (SpectralNormError): The other instance of error being combined. Returns: SpectralNormError: The total error after combination. **Example** >>> s1 = SpectralNormError(0.01) >>> s2 = SpectralNormError(0.02) >>> s1.combine(s2) SpectralNormError(0.03) """returnself.__class__(self.error+other.error)
[docs]@staticmethoddefget_error(approximate_op:Operator,exact_op:Operator):"""Compute spectral norm error between two operators. Args: approximate_op (Operator): The approximate operator. exact_op (Operator): The exact operator. Returns: float: The error between the exact operator and its approximation. **Example** >>> Op1 = qml.RY(0.40, 0) >>> Op2 = qml.RY(0.41, 0) >>> SpectralNormError.get_error(Op1, Op2) 0.004999994791668309 """wire_order=exact_op.wiresm1=qml.matrix(exact_op,wire_order=wire_order)m2=qml.matrix(approximate_op,wire_order=wire_order)returnqml.math.max(qml.math.svd(m1-m2,compute_uv=False))
def_compute_algo_error(tape)->dict[str,AlgorithmicError]:"""Given a quantum circuit (tape), this function computes the algorithmic error generated by standard PennyLane operations. Args: tape (.QuantumTape): The quantum circuit for which we compute errors Returns: dict[str->.AlgorithmicError]: dict with error name and combined error as key-value pair """algo_errors={}foropintape.operations:ifisinstance(op,ErrorOperation):op_error=op.error()error_name=op_error.__class__.__name__algo_error=algo_errors.get(error_name,None)error_value=op_errorifalgo_errorisNoneelsealgo_error.combine(op_error)algo_errors[error_name]=error_valuereturnalgo_errors