2.7. Sequencing PulseTemplates

In this example we will use the SequencePulseTemplate class to build a sequence of two of the simple table pulses defined in Modelling a Simple TablePulseTemplate. We will also map the parameters such that we can individually adapt values in either of the two subtemplates.

We start with the defintion of the TablePulseTemplate:

In [1]:
from qctoolkit.pulses import TablePT

template = TablePT(entries={0: [(0, 0),
                                ('ta', 'va', 'hold'),
                                ('tb', 'vb', 'linear'),
                                ('tend', 0, 'jump')]},identifier='foo')

Constructing a sequence of two of these requires us to set up a SequencePulseTemplate instance which expects a list of subtemplates. Optionally we can provide a set of external parametersand qctoolkit checks for us whether the result has exactly these:

In [2]:
from qctoolkit.pulses import SequencePT

external_parameters = ['ta', 'tb', 'tc', 'td', 'va', 'vb', 'tend']
first_mapping = {
    'ta': 'ta',
    'tb': 'tb',
    'va': 'va',
    'vb': 'vb',
    'tend': 'tend'
}
second_mapping = {
    'ta': 'tc',
    'tb': 'td',
    'va': 'vb',
    'vb': 'va + vb',
    'tend': '2 * tend'
}

# works
sequence = SequencePT(template,
                      (template, second_mapping))

# works, too
sequence = SequencePT(template,
                      (template, second_mapping),
                      external_parameters=external_parameters)

Here we see what happens if we provide the wrong external parameter set

In [3]:
try:
    wrong_external_parameters = external_parameters[:-1]
    sequence = SequencePT(template,
                          (template, second_mapping),
                          external_parameters=wrong_external_parameters)
except Exception as exception:
    print(type(exception).__name__, ':', exception)
MissingParameterDeclarationException : A mapping for template <qctoolkit.pulses.table_pulse_template.TablePulseTemplate object at 0x000002344538CAC8> requires a parameter 'tend' which has not been declared as an external parameter of the SequencePulseTemplate.

Our sequence now exposes the parameters declared in the external_parameters set:

In [4]:
print(sequence.parameter_names)
{'va', 'tend', 'tb', 'td', 'vb', 'tc', 'ta'}

The mappings are constructed such that the first occurance of our table template will receive its parameters without any modification. For the second, however, we renamed the parameters: The ‘tc’ parameter of the sequence is mapped to the ‘ta’ parameter of the table template instance; ‘td’ is mapped to ‘tb’ of the subtemplate, ‘vb’ (of the sequence template) to ‘va’ (of the subtemplate). The value for ‘vb’ of the subtemplate is computed as the sum of the values of ‘va’ and ‘vb’ passed to the sequence and the value for ‘tend’ is double before passing it on. We can do a variety of transformations here, allowing us to modify how parameters are handled to add additional computations in composed pulse templates or simply to avoid name collisions between subtemplate parameters.

Let’s throw in some values and plot our sequence:

In [5]:
%matplotlib notebook
from qctoolkit.pulses.plotting import plot

parameters = {'ta': 2,
              'va': 2,
              'tb': 4,
              'vb': 3,
              'tc': 5,
              'td': 11,
              'tend': 6}
_ = plot(sequence, parameters, sample_rate=100)

There is a shortcut to sequencing pulse templates via the ‘@’ operator. Of course, here we did not change the parameter mapping so the result looks different.

In [6]:
sequence_short = template @ template

_ = plot(sequence_short, parameters, sample_rate=100)