{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Mapping with the MappingPulseTemplate\n", "\n", "We will now have a look on how to remap parameters, channel ids and measurements. The definition of measurements is illustrated [here](Measurements.ipynb). The `MappingPulseTemplate` \n", "\n", "First we will have a look at the __mapping of parameters__:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2*pi/omega\n", "{'a', 'omega'}\n" ] } ], "source": [ "from qctoolkit.pulses import MappingPT, FunctionPT, SequencePT, AtomicMultiChannelPT\n", "\n", "sine = FunctionPT('a*sin(omega*t)', 't_duration')\n", "\n", "my_parameter_mapping = dict(t_duration='2*pi/omega', omega='omega', a='a')\n", "\n", "single_period_sine = MappingPT(sine, parameter_mapping=my_parameter_mapping)\n", "\n", "print(single_period_sine.duration)\n", "print(single_period_sine.parameter_names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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.\n", "\n", "You can, however, allow partial parameter mappings by passing `allow_partial_paramter_mappings=True` to the constructor." ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "MissingMappingException : The template needs a mapping function for parameter(s) {'a', 'omega'}\n", "\n", "2*pi/omega\n", "{'a', 'omega'}\n" ] } ], "source": [ "partial_parameter_mapping = dict(t_duration='2*pi/omega')\n", "try:\n", " single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping)\n", "except Exception as exception:\n", " print(type(exception).__name__, ':', exception)\n", "print('')\n", "\n", "\n", "single_period_sine = MappingPT(sine, parameter_mapping=partial_parameter_mapping, allow_partial_parameter_mapping=True)\n", "print(single_period_sine.duration)\n", "print(single_period_sine.parameter_names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Mapping of channel ids and measurement names:\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "ChannelMappingException : Channel is defined in subtemplate 1 and subtemplate 2\n" ] } ], "source": [ "sine_measurements = [('M', 't_duration/2', 't_duration')]\n", "sine = FunctionPT('a*sin(omega*t)', 't_duration', measurements=sine_measurements)\n", "\n", "cos_measurements = [('M', 0, 't_duration/2')]\n", "cos = FunctionPT('a*cos(omega*t)', 't_duration', measurements=cos_measurements)\n", "\n", "try:\n", " both = AtomicMultiChannelPT(sine, cos)\n", "except Exception as exception:\n", " print(type(exception).__name__, ':', exception)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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. " ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "remapped_cos channels: {'cos_channel'}\n", "remapped_cos measurements: {'M_cos'}\n", "\n", "remapped_sine channels: {'sin_channel'}\n", "remapped_sine measurements: {'M_sin'}\n", "\n", "{'cos_channel', 'sin_channel'}\n", "{'M_cos', 'M_sin'}\n" ] } ], "source": [ "cos_channel_mapping = dict(default='cos_channel')\n", "cos_measurement_mapping = dict(M='M_cos')\n", "remapped_cos = MappingPT(cos, channel_mapping=cos_channel_mapping, measurement_mapping=cos_measurement_mapping)\n", "print('remapped_cos channels:', remapped_cos.defined_channels)\n", "print('remapped_cos measurements:', remapped_cos.measurement_names)\n", "print()\n", "\n", "sine_channel_mapping = dict(default='sin_channel')\n", "sine_measurement_mapping = dict(M='M_sin')\n", "remapped_sine = MappingPT(sine, measurement_mapping=sine_measurement_mapping, channel_mapping=sine_channel_mapping)\n", "print('remapped_sine channels:', remapped_sine.defined_channels)\n", "print('remapped_sine measurements:', remapped_sine.measurement_names)\n", "print()\n", "\n", "both = AtomicMultiChannelPT(remapped_sine, remapped_cos)\n", "print(both.defined_channels)\n", "print(both.measurement_names)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Automatically created mapping templates\n", "\n", "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." ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "channels: {'default'}\n", "measurements {'M_sin'}\n", "parameters {'t_duration', 'a', 'omega'}\n", "\n", "channels: {'default'}\n", "measurements {'M_sin'}\n", "parameters {'a', 'omega'}\n", "\n" ] } ], "source": [ "auto_mapped = MappingPT.from_tuple((sine, sine_measurement_mapping))\n", "print('channels:', auto_mapped.defined_channels)\n", "print('measurements', auto_mapped.measurement_names)\n", "print('parameters', auto_mapped.parameter_names)\n", "print()\n", "\n", "auto_mapped = MappingPT.from_tuple((sine, sine_measurement_mapping, partial_parameter_mapping))\n", "print('channels:', auto_mapped.defined_channels)\n", "print('measurements', auto_mapped.measurement_names)\n", "print('parameters', auto_mapped.parameter_names)\n", "print()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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:" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'cos_channel', 'sin_channel'}\n", "{'M_cos', 'M_sin'}\n" ] } ], "source": [ "both_implicit = AtomicMultiChannelPT((sine, sine_channel_mapping, sine_measurement_mapping), \n", " (cos, cos_measurement_mapping, cos_channel_mapping))\n", "print(both_implicit.defined_channels)\n", "print(both_implicit.measurement_names)" ] } ], "metadata": { "kernelspec": { "display_name": "Python [conda env:qctoolkit]", "language": "python", "name": "conda-env-qctoolkit-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.5.2" } }, "nbformat": 4, "nbformat_minor": 2 }