# 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."""Contains class and methods for noise models"""importinspectimportpennylaneasqml
[docs]classNoiseModel:"""Builds a noise model based on the mappings of conditionals to callables that define noise operations using some optional metadata. Args: model_map (dict[BooleanFn -> Callable]): Data for applying the gate errors as a ``{conditional: noise_fn}`` dictionary. The signature of ``noise_fn`` should be ``noise_fn(op: Operation, **kwargs) -> None``, where ``op`` is the operation that the conditional evaluates and ``kwargs`` are the specified metadata arguments. meas_map (dict[BooleanFn -> Callable]): Data for adding the readout errors similar to ``model_map``. The signature of ``noise_fn`` must be ``noise_fn(mp: MeasurementProcess, **kwargs) -> None``, where ``mp`` is the measurement process that the conditional evaluates and ``kwargs`` are the specified metadata arguments. **kwargs: Keyword arguments for specifying metadata related to the noise model. .. note:: For each key-value pair of ``model_map`` and ``meas_map``: - The ``conditional`` should be either a function decorated with :class:`~.BooleanFn`, a callable object built via :ref:`constructor functions <intro_boolean_fn>` in the ``qml.noise`` module, or their bitwise combination. - The definition of ``noise_fn(Union[op, mp], **kwargs)`` should have the operations in the same order in which they are to be queued for an operation ``op`` or measurement process ``mp``, whenever the corresponding ``conditional`` evaluates to ``True``. - Each ``conditional`` in ``meas_map`` is evaluated on each measurement process in the order they are specified. The corresponding noise has to be added `before` the measurement, i.e., custom queing in ``noise_fn`` should not be done. **Example** .. code-block:: python # Set up the gate noise c0 = qml.noise.op_eq(qml.PauliX) | qml.noise.op_eq(qml.PauliY) c1 = qml.noise.op_eq(qml.Hadamard) & qml.noise.wires_in([0, 1]) def n0(op, **kwargs): qml.ThermalRelaxationError(0.4, kwargs["t1"], 0.2, 0.6, op.wires) n1 = qml.noise.partial_wires(qml.AmplitudeDamping, 0.4) # set up the readout noise m0 = qml.noise.meas_eq(qml.expval) & qml.noise.wires_in([0, 1]) n2 = qml.noise.partial_wires(qml.PhaseFlip, 0.2) # Set up noise model noise_model = qml.NoiseModel({c0: n0}, meas_map={m0:n2}, t1=0.04) noise_model += {c1: n1} >>> noise_model NoiseModel({ OpEq(PauliX) | OpEq(PauliY): n0 OpEq(Hadamard) & WiresIn([0, 1]): AmplitudeDamping(0.4, wires), }, meas_map = { MeasEq(expval) & WiresIn([0, 1]): PhaseFlip(p=0.2) }, t1=0.04) """def__init__(self,model_map,meas_map=None,**kwargs):self.check_model(model_map)self._model_map=model_mapifmeas_mapisnotNone:self.check_model(meas_map)self._meas_map=meas_mapor{}self._metadata=kwargs@propertydefmodel_map(self):"""Gives the conditional model for the noise model."""returnself._model_map@propertydefmeas_map(self):"""Gives the measurement model for the noise model."""returnself._meas_map@propertydefmetadata(self):"""Gives the metadata for the noise model."""returnself._metadatadef__add__(self,data):ifnotisinstance(data,NoiseModel):ms_=data.pop("meas_map",{})mt_={key:data.pop(key)forkeyinlist(filter(lambdak:isinstance(k,str),data))}returnNoiseModel({**self.model_map,**data},{**self.meas_map,**ms_},**{**self.metadata,**mt_},)returnNoiseModel({**self.model_map,**data.model_map},{**self.meas_map,**data.meas_map},**{**self.metadata,**data.metadata},)def__radd__(self,data):returnself.__add__(data)def__sub__(self,data):ifnotisinstance(data,NoiseModel):ms_=data.pop("meas_map",{})mt_={key:data.pop(key)forkeyinlist(filter(lambdak:isinstance(k,str),data))}returnNoiseModel({k:vfork,vinself.model_map.items()ifknotindata},meas_map={k:vfork,vinself.meas_map.items()ifknotinms_},**{k:vfork,vinself.metadata.items()ifknotinmt_},)returnNoiseModel({k:vfork,vinself.model_map.items()ifknotindata.model_map},**dict({k:vfork,vinself.metadata.items()ifknotindata.metadata}),)def__eq__(self,other):forkeyin["model_map","meas_map"]:formodel1,model2inzip(getattr(self,key).items(),getattr(other,key).items()):(func1,noise1),(func2,noise2)=model1,model2ifgetattr(func1,"condition",func1.fn)!=getattr(func2,"condition",func2.fn):returnFalseifnoise1!=noise2:returnFalsereturnself.metadata==other.metadatadef__repr__(self):model_str="NoiseModel({\n"forkey,valinself.model_map.items():model_str+=" "+f"{key}: {val.__name__}"+"\n"ifself._meas_map:model_str+="},\nmeas_map = {\n"forkey,valinself.meas_map.items():model_str+=" "+f"{key}: {val.__name__}"+"\n"model_str+="}, "forkey,valinself._metadata.items():model_str+=f"{key} = {val}, "model_str=model_str[:-2]+")"returnmodel_str
[docs]@staticmethoddefcheck_model(model:dict)->None:"""Method to validate a ``{conditional -> noise_fn}`` map for constructing a noise model."""forcondition,noiseinmodel.items():ifnotisinstance(condition,qml.BooleanFn):raiseValueError(f"{condition} must be a boolean conditional, i.e., an instance of ""BooleanFn or one of its subclasses.")final_parameter=list(inspect.signature(noise).parameters.values())[-1]iffinal_parameter.kind!=final_parameter.VAR_KEYWORD:raiseValueError(f"{noise} provided for {condition} must accept **kwargs ""as the last argument in its signature.")