{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Conditional Execution\n", "\n", "The qctoolkit is desinged to support conditional execution of pulse (segments). This allows pulse designers to play back different waveforms depending on, e.g., environment data or state measurements of the quantum dot. Conditional execution may be implemented via trigger-based jumps to instructions directly on the playback device or emulated in software by choosing which pulse to send to the hardware for playback, if the hardware itself does not support branching.\n", "\n", "Since the decision whether a condition will be evaluated software- or hardware-based depends on the hardware setup of the experiment and not on the pulse template the qctoolkit relies on an indirection scheme for conditions which is similar to the handling of parameters, as you will see in the following.\n", "\n", "qctoolkit offers two `PulseTemplate` subclasses for conditional execution: `LoopPulseTemplate` and `BranchPulseTemplate` (*Note: BranchPulseTemplate is currently pending implementation ([issue 22](https://github.com/qutech/qc-toolkit/issues/22))*). \n", "\n", "`LoopPulseTemplate` takes an identifier for a condition and a subtemplate which is repeated as long as the condition evaluates to `True`. Let's assume that we want to construct a pulse that waits until some initialization is completed using a `TablePulseTemplate` representing a zero-pulse of length 5 and a `LoopPulseTemplate`:" ] }, { "cell_type": "code", "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [], "source": [ "from qctoolkit.pulses import LoopPulseTemplate, TablePulseTemplate\n", "\n", "wait_template = TablePulseTemplate()\n", "wait_template.add_entry(5, 0)\n", "\n", "loop_template = LoopPulseTemplate('initialization_in_progress', wait_template)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`loop_template` is now configured to evaluate a condition called 'initialization_in_progress'. How this condition is implemented needs not to be specified to declare pulse templates." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "\n", "We will now look into the actual implementation of conditions. The abstract interface of conditions is the `Condition` class. As mentioned in the beginning, conditions can be evaluated software- and hardware-based. The classes `SoftwareCondition` and `HardwareCondition` represent this in the qctoolkit. Note that these classes don't do the actual evaluation but encapsulate it against the `Sequencer` and are used to generate correct sequences for both cases. Instances of `Condition`s are passed directly into the `Sequencer` and mapped to the `PulseTemplate`s via the identifier, similar to parameters.\n", "\n", "## Software-Based Conditions\n", "`SoftwareCondition` takes a callback function which is called to evaluate the condition (and thus must return a boolean value). During the sequencing process, this function will be called. If the return value is `True`, the subtemplate will be included in the instruction sequence and another evaluation will be made until the return value is `False`. The generated instruction sequence will thus contain a number of repetitions of the subtemplate but no actual jumping instructions, the loop is essentially unrolled. The callback function is passed an integer value indicating the current iteration of the evaluation.\n", "\n", "As an example, we could use this to repeat the `wait_template` a fixed number of times, say 5, as follows:" ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[, , , , , ]\n" ] } ], "source": [ "from qctoolkit.pulses import SoftwareCondition, Sequencer\n", "\n", "constant_repeat_condition = SoftwareCondition(lambda x: x < 5)\n", "conditions = {'initialization_in_progress': constant_repeat_condition}\n", "\n", "s = Sequencer()\n", "parameters = {}\n", "s.push(loop_template, parameters, conditions)\n", "instructions = s.build()\n", "print(instructions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "We obtain an instruction sequence that repeats an execution instruction (for the `wait_template` waveform) five times. This is, of course, a very simple example. The callback function passed into the `SoftwareCondition` instance will more likely evaluate some measured data. Since this might not always be available in the sequencing pass, the callback may return `None`, which will interrupt the sequencing process similar to the [`requires_stop` method of the `Parameter` class](05Parameters.ipynb)." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Hardware-Based Conditions\n", "Since software-based evaluation of conditions is slow and might interrupt the sequencing process, it might not always be applicable. If supported by the hardware, hardware-based condition evaluation is preferrable. For the sequencing process, this is represented by instances of `HardwareCondition`, which only take some identifier of the hardware trigger. This must first be obtained from the hardware *currently not implemented* and is embedded in the generated instruction sequence which will contain jump instructions.\n", "\n", "Assuming we have a hardware setup with a trigger that fires continuously until temperature threshold is reached and we want our pulse from above to repeat as long as the trigger fires. We can realize this as follows:" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "[, , , ]\n" ] } ], "source": [ "from qctoolkit.pulses import HardwareCondition, Trigger\n", "\n", "# stub representation for the trigger which must be obtained from the hardware in a real use case\n", "temperature_trigger = Trigger()\n", "\n", "temperature_trigger_condition = HardwareCondition(temperature_trigger)\n", "conditions = {'initialization_in_progress': temperature_trigger_condition}\n", "\n", "s = Sequencer()\n", "parameters = {}\n", "s.push(loop_template, parameters, conditions)\n", "instructions = s.build()\n", "print(instructions)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "As you can see in the output, the sequencing process now procudes instructions that perform conditional jumps and returns with goto instructions. The details are omitted here, suffice it to say that the trigger is embedded in the conditional jump instruction and this sequence will loop on the hardware as long as the trigger fires." ] } ], "metadata": { "kernelspec": { "display_name": "Python 3", "language": "python", "name": "python3" }, "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.4.4" } }, "nbformat": 4, "nbformat_minor": 0 }