"""This module defines the ConstantPulseTemplate, a pulse tempalte representating a pulse with constant values on all channels
Classes:
- ConstantPulseTemplate: Defines a pulse via channel-value pairs
- ConstantPulseWaveform: A waveform instantiated from a TablePulseTemplate by providing values for its
declared parameters.
"""
import logging
import numbers
from typing import Any, Dict, List, Optional, Union, Mapping, AbstractSet
from qupulse.program.waveforms import ConstantWaveform
from qupulse.utils.types import TimeType, ChannelID
from qupulse.utils import cached_property
from qupulse.expressions import ExpressionScalar, ExpressionLike
from qupulse.pulses.multi_channel_pulse_template import MultiChannelWaveform
from qupulse.pulses.pulse_template import AtomicPulseTemplate, MeasurementDeclaration
from qupulse.serialization import PulseRegistryType
__all__ = ["ConstantPulseTemplate"]
[docs]class ConstantPulseTemplate(AtomicPulseTemplate): # type: ignore
[docs] def __init__(self, duration: ExpressionLike, amplitude_dict: Dict[ChannelID, ExpressionLike],
identifier: Optional[str] = None,
name: Optional[str] = None,
measurements: Optional[List[MeasurementDeclaration]] = None,
registry: PulseRegistryType=None) -> None:
"""An atomic pulse template qupulse representing a multi-channel pulse with constant values.
Args:
duration: Duration of the template
amplitude_dict: Dictionary with values for the channels
name: Name for the template. Not used by qupulse
"""
super().__init__(identifier=identifier, measurements=measurements)
# we special case numeric values in this PulseTemplate for performance reasons
self._duration = duration if isinstance(duration, (float, int, TimeType)) else ExpressionScalar(duration)
self._amplitude_dict: Mapping[ChannelID, Union[float, ExpressionScalar]] = {
channel: value if isinstance(value, (float, int)) else ExpressionScalar(value)
for channel, value in amplitude_dict.items()}
if name is None:
name = 'constant_pulse'
self._name = name
self._register(registry)
def _as_expression(self):
return self._amplitude_dict
def __str__(self) -> str:
return '<{} at %x{}: {}>'.format(self.__class__.__name__, '%x' % id(self), self._name)
[docs] def get_serialization_data(self, serializer=None) -> Any:
if serializer is not None:
raise NotImplementedError("ConstantPulseTemplate does not implement legacy serialization.")
data = super().get_serialization_data()
data.update({
'name': self._name,
'duration': self._duration,
'amplitude_dict': self._amplitude_dict,
'measurements': self.measurement_declarations
})
return data
[docs] @classmethod
def deserialize(cls, serializer: Optional = None, **kwargs) -> 'ConstantPulseTemplate':
assert serializer is None, f"{cls} does not support legacy deserialization"
# this is for backwards compatible deserialization.
amplitudes = kwargs.pop('#amplitudes', None)
if amplitudes is not None:
kwargs['amplitude_dict'] = amplitudes
return cls(**kwargs)
@property
def integral(self) -> Dict[ChannelID, ExpressionScalar]:
"""Returns an expression giving the integral over the pulse."""
return {c: self.duration * self._amplitude_dict[c] for c in self._amplitude_dict}
@cached_property
def parameter_names(self) -> AbstractSet[str]:
"""The set of names of parameters required to instantiate this PulseTemplate."""
parameters = []
for amplitude in self._amplitude_dict.values():
if hasattr(amplitude, 'variables'):
parameters.extend(amplitude.variables)
if hasattr(self._duration, 'variables'):
parameters.extend(self._duration.variables)
parameters.extend(self.measurement_parameters)
return frozenset(parameters)
@cached_property
def duration(self) -> ExpressionScalar:
"""An expression for the duration of this PulseTemplate."""
if isinstance(self._duration, ExpressionScalar):
return self._duration
else:
return ExpressionScalar(self._duration)
@property
def defined_channels(self) -> AbstractSet['ChannelID']:
"""Returns the number of hardware output channels this PulseTemplate defines."""
return set(self._amplitude_dict)
@property
def initial_values(self) -> Dict[ChannelID, ExpressionScalar]:
return {ch: ExpressionScalar(val) for ch, val in self._amplitude_dict.items()}
@property
def final_values(self) -> Dict[ChannelID, ExpressionScalar]:
return {ch: ExpressionScalar(val) for ch, val in self._amplitude_dict.items()}