2.6. Mapping with the MappingPulseTemplate¶
We will now have a look on how to remap parameters, channel ids and
measurements. The definition of measurements is illustrated
here. The MappingPulseTemplate
First we will have a look at the mapping of parameters:
In [1]:
from qctoolkit.pulses import MappingPT, FunctionPT, SequencePT, AtomicMultiChannelPT
sine = FunctionPT('a*sin(omega*t)', 't_duration')
my_parameter_mapping = dict(t_duration='2*pi/omega', omega='omega', a='a')
single_period_sine = MappingPT(sine, parameter_mapping=my_parameter_mapping)
print(single_period_sine.duration)
print(single_period_sine.parameter_names)
2*pi/omega
{'a', 'omega'}
Notice that we had to give mappings for all parameters, not only for the
ones which changed. If we omit some of the encapsulated pulse tempaltes
parameters an MissingMappingException
is raised. This is done to
enforce active thinking.
You can, however, allow partial parameter mappings by passing
allow_partial_paramter_mappings=True
to the constructor.
In [2]:
partial_parameter_mapping = dict(t_duration='2*pi/omega')
try:
single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping)
except Exception as exception:
print(type(exception).__name__, ':', exception)
print('')
single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping, allow_partial_parameter_mapping=True)
print(single_period_sine.duration)
print(single_period_sine.parameter_names)
MissingMappingException : The template <qctoolkit.pulses.function_pulse_template.FunctionPulseTemplate object at 0x0000025E3A5DF4A8> needs a mapping function for parameter(s) {'a', 'omega'}
2*pi/omega
{'a', 'omega'}
2.6.1. Mapping of channel ids and measurement names:¶
Sometimes it is necessary to rename channels or measurements. Here we
see a case where we want to play a sine and a cosine in parallel by
using the AtomicMultiChannelPulseTemplate
. Of course, this doesn’t
work as both pulses are by default defined on the ‘default’ channel.
In [3]:
sine_measurements = [('M', 't_duration/2', 't_duration')]
sine = FunctionPT('a*sin(omega*t)', 't_duration', measurements=sine_measurements)
cos_measurements = [('M', 0, 't_duration/2')]
cos = FunctionPT('a*cos(omega*t)', 't_duration', measurements=cos_measurements)
try:
both = AtomicMultiChannelPT(sine, cos)
except Exception as exception:
print(type(exception).__name__, ':', exception)
ChannelMappingException : Channel <default> is defined in subtemplate 1 and subtemplate 2
The solution is to use the MappingPT
and rename the channels as we
see in the next cell. Additionally, we want to distinguish between the
measurements, so we rename them, too.
In [4]:
cos_channel_mapping = dict(default='cos_channel')
cos_measurement_mapping = dict(M='M_cos')
remapped_cos = MappingPT(cos, channel_mapping=cos_channel_mapping, measurement_mapping=cos_measurement_mapping)
print('remapped_cos channels:', remapped_cos.defined_channels)
print('remapped_cos measurements:', remapped_cos.measurement_names)
print()
sine_channel_mapping = dict(default='sin_channel')
sine_measurement_mapping = dict(M='M_sin')
remapped_sine = MappingPT(sine, measurement_mapping=sine_measurement_mapping, channel_mapping=sine_channel_mapping)
print('remapped_sine channels:', remapped_sine.defined_channels)
print('remapped_sine measurements:', remapped_sine.measurement_names)
print()
both = AtomicMultiChannelPT(remapped_sine, remapped_cos)
print(both.defined_channels)
print(both.measurement_names)
remapped_cos channels: {'cos_channel'}
remapped_cos measurements: {'M_cos'}
remapped_sine channels: {'sin_channel'}
remapped_sine measurements: {'M_sin'}
{'cos_channel', 'sin_channel'}
{'M_cos', 'M_sin'}
2.6.2. Automatically created mapping templates¶
Besides the explicit usage of the template it is also used implicitly in
some cases. All implicit uses make use of the static member function
MappingPulseTemplate.from_tuple
. This ‘constructor’ automatically
decides which mapping belongs to which entity.
In [5]:
auto_mapped = MappingPT.from_tuple((sine, sine_measurement_mapping))
print('channels:', auto_mapped.defined_channels)
print('measurements', auto_mapped.measurement_names)
print('parameters', auto_mapped.parameter_names)
print()
auto_mapped = MappingPT.from_tuple((sine, sine_measurement_mapping, partial_parameter_mapping))
print('channels:', auto_mapped.defined_channels)
print('measurements', auto_mapped.measurement_names)
print('parameters', auto_mapped.parameter_names)
print()
channels: {'default'}
measurements {'M_sin'}
parameters {'t_duration', 'a', 'omega'}
channels: {'default'}
measurements {'M_sin'}
parameters {'a', 'omega'}
In many cases, you do not need to create the MappingPT yourself. Most PulseParameters accept a mapping tuple like the ones used in the last cell. We could create our combined pulse also by using this implicit conversion:
In [6]:
both_implicit = AtomicMultiChannelPT((sine, sine_channel_mapping, sine_measurement_mapping),
(cos, cos_measurement_mapping, cos_channel_mapping))
print(both_implicit.defined_channels)
print(both_implicit.measurement_names)
{'cos_channel', 'sin_channel'}
{'M_cos', 'M_sin'}