Source code for qiskit_experiments.calibration_management.basis_gate_library
# This code is part of Qiskit.## (C) Copyright IBM 2021.## This code is licensed under the Apache License, Version 2.0. You may# obtain a copy of this license in the LICENSE.txt file in the root directory# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.## Any modifications or derivative works of this code must retain this# copyright notice, and modified files need to carry a notice indicating# that they have been altered from the originals."""A collections of libraries to setup Calibrations.Note that the set of available libraries will be extended in future releases."""fromabcimportABC,abstractmethodfromcollections.abcimportMappingfromtypingimportAny,Dict,List,Optional,Setfromwarningsimportwarnimportnumpyasnpfromqiskit.circuitimportParameterfromqiskitimportpulsefromqiskit.pulseimportScheduleBlockfromqiskit.utils.deprecationimportdeprecate_funcfromqiskit_experiments.calibration_management.calibration_key_typesimportDefaultCalValuefromqiskit_experiments.exceptionsimportCalibrationError
[docs]classBasisGateLibrary(ABC,Mapping):"""A base class for libraries of basis gates to make it easier to setup Calibrations."""# Location where default parameter values are stored. These may be updated at construction.__default_values__={}# Parameters that do not belong to a schedule, a set of names__parameters_without_schedule__=set()@deprecate_func(since="0.8",package_name="qiskit-experiments",additional_msg=("Due to the deprecation of Qiskit Pulse, support for pulse ""gate calibrations has been deprecated."),)def__init__(self,basis_gates:Optional[List[str]]=None,default_values:Optional[Dict]=None,**extra_kwargs,):"""Setup the library. Args: basis_gates: The basis gates to generate. default_values: A dictionary to override library default parameter values. extra_kwargs: Extra key-word arguments of the subclasses that are saved to be able to reconstruct the library using the :meth:`__init__` method. Raises: CalibrationError: If on of the given basis gates is not supported by the library. """# Update the default values.self._extra_kwargs=extra_kwargsself._default_values=self.__default_values__.copy()ifdefault_valuesisnotNone:self._default_values.update(default_values)ifbasis_gatesisNone:basis_gates=list(self.__supported_gates__)forgateinbasis_gates:ifgatenotinself.__supported_gates__:raiseCalibrationError(f"Gate {gate} is not supported by {self.__class__.__name__}. "f"Supported gates are: {self.__supported_gates__}.")self._schedules=self._build_schedules(set(basis_gates))@property@abstractmethoddef__supported_gates__(self)->Dict[str,int]:"""Return the supported gates of the library. The key is the name of the gate and the value is the number of qubits it applies to. """raiseNotImplementedError
[docs]def__getitem__(self,name:str)->ScheduleBlock:"""Return the schedule."""ifnamenotinself._schedules:raiseCalibrationError(f"Gate {name} is not contained in {self.__class__.__name__}.")returnself._schedules[name]
def__contains__(self,name:str)->bool:"""Check if the basis gate is in the library."""returnnameinself._schedulesdef__hash__(self)->int:"""Return the hash of the library by computing the hash of the schedule strings."""data_to_hash=[]forname,scheduleinsorted(self._schedules.items()):data_to_hash.append((name,str(schedule),self.__supported_gates__[name]))returnhash(tuple(data_to_hash))
[docs]def__len__(self):"""The length of the library defined as the number of basis gates."""returnlen(self._schedules)
def__iter__(self):"""Return an iterator over the basis gate library."""returniter(self._schedules)
[docs]defnum_qubits(self,name:str)->int:"""Return the number of qubits that the schedule with the given name acts on."""returnself.__supported_gates__[name]
@propertydefbasis_gates(self)->List[str]:"""Return the basis gates supported by the library."""returnlist(self._schedules)
[docs]@abstractmethoddefdefault_values(self)->List[DefaultCalValue]:"""Return the default values for the parameters. Returns A list of tuples is returned. These tuples are structured so that instances of :class:`.Calibrations` can call :meth:`.Calibrations.add_parameter_value` on the tuples. """
@abstractmethoddef_build_schedules(self,basis_gates:Set[str])->Dict[str,ScheduleBlock]:"""Build the schedules stored in the library. This method is called as the last step in the :meth:`__init__`. Subclasses must implement :meth:`_build_schedules` to build the schedules of the library based on the inputs given to the :meth:`__init__` method. Args: basis_gates: The set of basis gates to build. These will be the supported gates or a subset thereof. Returns: A dictionary where the keys are the names of the schedules/basis gates and the values are the corresponding schedules. """
[docs]defconfig(self)->Dict[str,Any]:"""Return the settings used to initialize the library."""kwargs={"basis_gates":self.basis_gates,"default_values":self._default_values}kwargs.update(self._extra_kwargs)return{"class":self.__class__.__name__,"kwargs":kwargs,"hash":hash(self),}
[docs]@classmethoddeffrom_config(cls,config:Dict)->"BasisGateLibrary":"""Deserialize the library given the input dictionary"""library=cls(**config["kwargs"])ifhash(library)!=config["hash"]:warn("Deserialized basis gate library's hash does not match the hash of the serialized ""library. Typically, the hash changes when the internal structure of the template ""schedules has been changed.")returnlibrary
def__json_encode__(self):"""Convert to format that can be JSON serialized."""returnself.config()@classmethoddef__json_decode__(cls,value:Dict[str,Any])->"BasisGateLibrary":"""Load from JSON compatible format."""returncls.from_config(value)
[docs]classFixedFrequencyTransmon(BasisGateLibrary):r"""A library of gates for fixed-frequency superconducting qubit architectures. Note that for now this library supports single-qubit gates and will be extended in the future. Provided gates: - x: :math:`\pi` pulse around the x-axis. - sx: :math:`\pi/2` pulse around the x-axis. - y: :math:`\pi` pulse around the y-axis. - sy: :math:`\pi/2` pulse around the y-axis. Pulse parameters: - duration: Duration of the pulses Default value: 160 samples. - σ: Standard deviation of the pulses Default value: ``duration / 4``. - β: DRAG parameter of the pulses Default value: 0. - amp: Magnitude of the complex amplitude of the pulses. If the parameters are linked then ``x`` and ``y`` share the same parameter and ``sx`` and ``sy`` share the same parameter. Default value: 50% of the maximum output for ``x`` and ``y`` and 25% of the maximum output for ``sx`` and ``sy``. Note that the user provided default amplitude in the ``__init__`` method sets the default amplitude of the ``x`` and ``y`` pulses. The amplitude of the ``sx`` and ``sy`` pulses is half the provided value. - angle: The phase of the complex amplitude of the pulses. Parameters without schedule: - meas_freq: frequency of the measurement drives. - drive_freq: frequency of the qubit drives. Note that the β and amp parameters may be linked between the x and y as well as between the sx and sy pulses. All pulses share the same duration and σ parameters. """__default_values__={"duration":160,"amp":0.5,"β":0.0,"angle":0.0}__parameters_without_schedule__={"meas_freq","drive_freq"}def__init__(self,basis_gates:Optional[List[str]]=None,default_values:Optional[Dict]=None,link_parameters:bool=True,):"""Setup the schedules. Args: basis_gates: The basis gates to generate. default_values: Default values for the parameters this dictionary can contain the following keys: "duration", "amp", "β", and "σ". If "σ" is not provided this library will take one fourth of the pulse duration as default value. link_parameters: If set to ``True``, then the amplitude and DRAG parameters of the :math:`X` and :math:`Y` gates will be linked as well as those of the :math:`SX` and :math:`SY` gates. """self._link_parameters=link_parametersextra_kwargs={"link_parameters":link_parameters}super().__init__(basis_gates,default_values,**extra_kwargs)@propertydef__supported_gates__(self)->Dict[str,int]:"""The gates that this library supports."""return{"x":1,"y":1,"sx":1,"sy":1}def_build_schedules(self,basis_gates:Set[str])->Dict[str,ScheduleBlock]:"""Build the schedule of the class."""dur=Parameter("duration")sigma=Parameter("σ")x_amp,x_beta,x_angle=Parameter("amp"),Parameter("β"),Parameter("angle")ifself._link_parameters:y_amp,y_beta,y_angle=x_amp,x_beta,x_angle+np.pi/2else:y_amp,y_beta,y_angle=Parameter("amp"),Parameter("β"),Parameter("angle")sx_amp,sx_beta,sx_angle=Parameter("amp"),Parameter("β"),Parameter("angle")ifself._link_parameters:sy_amp,sy_beta,sy_angle=sx_amp,sx_beta,sx_angle+np.pi/2else:sy_amp,sy_beta,sy_angle=Parameter("amp"),Parameter("β"),Parameter("angle")# Create the schedules for the gatessched_x=self._single_qubit_schedule("x",dur,x_amp,sigma,x_beta,x_angle)sched_y=self._single_qubit_schedule("y",dur,y_amp,sigma,y_beta,y_angle)sched_sx=self._single_qubit_schedule("sx",dur,sx_amp,sigma,sx_beta,sx_angle)sched_sy=self._single_qubit_schedule("sy",dur,sy_amp,sigma,sy_beta,sy_angle)schedules={}forschedin[sched_x,sched_y,sched_sx,sched_sy]:ifsched.nameinbasis_gates:schedules[sched.name]=schedreturnschedules@staticmethoddef_single_qubit_schedule(name:str,dur:Parameter,amp:Parameter,sigma:Parameter,beta:Parameter,angle:Parameter,)->ScheduleBlock:"""Build a single qubit pulse."""chan=pulse.DriveChannel(Parameter("ch0"))withpulse.build(name=name)assched:pulse.play(pulse.Drag(duration=dur,amp=amp,sigma=sigma,beta=beta,angle=angle),chan)returnsched
[docs]defdefault_values(self)->List[DefaultCalValue]:"""Return the default values for the parameters. Returns A list of tuples is returned. These tuples are structured so that instances of :class:`.Calibrations` can call :meth:`.Calibrations.add_parameter_value` on the tuples. """defaults=[]forname,scheduleinself.items():forparaminschedule.parameters:if"ch"notinparam.name:if"y"innameandself._link_parameters:continueifparam.name=="σ"and"σ"notinself._default_values:value=self._default_values["duration"]/4else:value=self._default_values[param.name]ifnamein{"sx","sy"}andparam.name=="amp":value/=2.0if"y"innameandparam.name=="angle":value+=np.pi/2defaults.append(DefaultCalValue(value,param.name,tuple(),name))returndefaults
[docs]classEchoedCrossResonance(BasisGateLibrary):r"""A library for echoed cross-resonance gates. The ``cr45p`` and ``cr45m`` include a pulse on the control qubit and optionally a pulse on the target qubit. Provided gates: - cr45p: GaussianSquare cross-resonance gate for a :math:`+\pi/4` rotation. - cr45m: GaussianSquare cross-resonance gate for a :math:`-\pi/4` rotation. - ecr: Echoed cross-resonance gate defined as ``cr45p - x - cr45m``. - rzx: RZXGate built from the ecr as ``cr45p - x - cr45m - x``. Required gates: - x: the x gate is defined outside of this library, see :class:`.FixedFrequencyTransmon`. Pulse parameters: - tgt_amp: The amplitude of the pulse applied to the target qubit. Default value: 0. - σ: The standard deviation of the flanks. Default value: 64 samples. - amp: The amplitude of the pulses applied to the control qubit. Default value: 50%. - duration: The duration of the cr45p and cr45m pulses. Default value: 1168 samples. - risefall: The number of σ's in the flanks of the pulses. Default value: 2. """__default_values__={"tgt_amp":0.0,"tgt_angle":0.0,"amp":0.5,"angle":0.0,"σ":64,"risefall":2,"duration":1168,}def__init__(self,basis_gates:Optional[List[str]]=None,default_values:Optional[Dict]=None,target_pulses:bool=True,):"""Setup the library. Args: basis_gates: The basis gates to generate. default_values: A dictionary to override library default parameter values. target_pulses: If True (the default) then drives will be added to the target qubit during the CR tones on the control qubit. """self._target_pulses=target_pulsessuper().__init__(basis_gates,default_values)@propertydef__supported_gates__(self)->Dict[str,int]:"""The supported gates of the library are two-qubit pulses for the ecr gate."""return{"cr45p":2,"cr45m":2,"ecr":2,"rzx":2}
[docs]defdefault_values(self)->List[DefaultCalValue]:"""The default values of the CR library."""defaults=[]forname,scheduleinself.items():forparaminschedule.parameters:if"ch"notinparam.name:value=self._default_values[param.name]defaults.append(DefaultCalValue(value,param.name,tuple(),name))returndefaults
def_build_schedules(self,basis_gates:Set[str])->Dict[str,ScheduleBlock]:"""Build the schedules of the CR library."""schedules={}tgt_amp=Parameter("tgt_amp")tgt_angle=Parameter("tgt_angle")sigma=Parameter("σ")cr_amp=Parameter("amp")cr_angle=Parameter("angle")cr_dur=Parameter("duration")cr_rf=Parameter("risefall")t_chan_idx=Parameter("ch1")u_chan_idx=Parameter("ch0.1")t_chan=pulse.DriveChannel(t_chan_idx)u_chan=pulse.ControlChannel(u_chan_idx)if"cr45p"inbasis_gates:withpulse.build(name="cr45p")ascr45p:pulse.play(pulse.GaussianSquare(cr_dur,cr_amp,angle=cr_angle,risefall_sigma_ratio=cr_rf,sigma=sigma),u_chan,)ifself._target_pulses:pulse.play(pulse.GaussianSquare(cr_dur,tgt_amp,angle=tgt_angle,risefall_sigma_ratio=cr_rf,sigma=sigma,),t_chan,)schedules["cr45p"]=cr45pif"cr45m"inbasis_gates:withpulse.build(name="cr45m")ascr45m:pulse.play(pulse.GaussianSquare(cr_dur,cr_amp,angle=cr_angle+np.pi,risefall_sigma_ratio=cr_rf,sigma=sigma,),u_chan,)ifself._target_pulses:pulse.play(pulse.GaussianSquare(cr_dur,tgt_amp,angle=tgt_angle+np.pi,risefall_sigma_ratio=cr_rf,sigma=sigma,),t_chan,)schedules["cr45m"]=cr45m# Echoed Cross-Resonance gateif"ecr"inbasis_gates:withpulse.build(name="ecr")asecr:withpulse.align_sequential():pulse.reference("cr45p","q0","q1")pulse.reference("x","q0")pulse.reference("cr45m","q0","q1")schedules["ecr"]=ecr# RZXGate built from Echoed Cross-Resonance gateif"rzx"inbasis_gates:withpulse.build(name="rzx")asrzx:withpulse.align_sequential():pulse.reference("cr45p","q0","q1")pulse.reference("x","q0")pulse.reference("cr45m","q0","q1")pulse.reference("x","q0")schedules["rzx"]=rzxreturnschedules