From 5a3e7cac6f121afb78a53aa92ed041fac0014e95 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 16 Nov 2015 12:43:05 +0100 Subject: [PATCH 01/33] Import statements are now expressed as full package and module paths. --- qctoolkit/pulses/__init__.py | 24 ++-- qctoolkit/pulses/conditions.py | 122 ++++++------------ qctoolkit/pulses/function_pulse_template.py | 10 +- qctoolkit/pulses/instructions.py | 2 +- qctoolkit/pulses/loop_pulse_template.py | 11 +- qctoolkit/pulses/plotting.py | 6 +- qctoolkit/pulses/pulse_template.py | 4 +- qctoolkit/pulses/repetition_pulse_template.py | 10 +- qctoolkit/pulses/sequence_pulse_template.py | 10 +- qctoolkit/pulses/sequencing.py | 4 +- qctoolkit/pulses/table_pulse_template.py | 12 +- 11 files changed, 89 insertions(+), 126 deletions(-) diff --git a/qctoolkit/pulses/__init__.py b/qctoolkit/pulses/__init__.py index 04ab596fd..573224cf8 100644 --- a/qctoolkit/pulses/__init__.py +++ b/qctoolkit/pulses/__init__.py @@ -1,12 +1,12 @@ -from .branch_pulse_template import * -from .conditions import * -from .function_pulse_template import * -from .instructions import * -from .loop_pulse_template import * -from .parameters import * -from .plotting import * -from .pulse_template import * -from .repetition_pulse_template import * -from .sequence_pulse_template import * -from .sequencing import * -from .table_pulse_template import * +from qctoolkit.pulses.branch_pulse_template import * +from qctoolkit.pulses.conditions import * +from qctoolkit.pulses.function_pulse_template import * +from qctoolkit.pulses.instructions import * +from qctoolkit.pulses.loop_pulse_template import * +from qctoolkit.pulses.parameters import * +from qctoolkit.pulses.plotting import * +from qctoolkit.pulses.pulse_template import * +from qctoolkit.pulses.repetition_pulse_template import * +from qctoolkit.pulses.sequence_pulse_template import * +from qctoolkit.pulses.sequencing import * +from qctoolkit.pulses.table_pulse_template import * diff --git a/qctoolkit/pulses/conditions.py b/qctoolkit/pulses/conditions.py index 7f2e5a810..fa19c5f2a 100644 --- a/qctoolkit/pulses/conditions.py +++ b/qctoolkit/pulses/conditions.py @@ -6,14 +6,15 @@ """RELATED THIRD PARTY IMPORTS""" """LOCAL IMPORTS""" -from .parameters import Parameter -from .sequencing import SequencingElement, Sequencer -from .instructions import InstructionBlock, InstructionPointer, Trigger +from qctoolkit.pulses import parameters +from qctoolkit.pulses import sequencing +from qctoolkit.pulses import instructions logger = logging.getLogger(__name__) __all__ = ["Condition", "ConditionEvaluationException", "SoftwareCondition", "HardwareCondition"] + class Condition(metaclass = ABCMeta): """A condition on which the execution of a pulse may depend. @@ -31,12 +32,12 @@ def requires_stop(self) -> bool: @abstractmethod def build_sequence_loop(self, - delegator: SequencingElement, - body: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], + delegator: sequencing.SequencingElement, + body: sequencing.SequencingElement, + sequencer: sequencing.Sequencer, + parameters: Dict[str, parameters.Parameter], conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: + instruction_block: instructions.InstructionBlock) -> None: """Translate a looping SequencingElement using this Condition into an instruction sequence for the given instruction block using sequencer and the given parameter sets. delegator refers to the SequencingElement which has delegated the invocation of build_sequence to this Condition object. body is the loop body element. @@ -45,13 +46,13 @@ def build_sequence_loop(self, @abstractmethod def build_sequence_branch(self, - delegator: SequencingElement, - if_branch: SequencingElement, - else_branch: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], + delegator: sequencing.SequencingElement, + if_branch: sequencing.SequencingElement, + else_branch: sequencing.SequencingElement, + sequencer: sequencing.Sequencer, + parameters: Dict[str, parameters.Parameter], conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: + instruction_block: instructions.InstructionBlock) -> None: """Translate a branching SequencingElement using this Condition into an instruction sequence for the given instruction block using sequencer and the given parameter sets. delegator refers to the SequencingElement which has delegated the invocation of build_sequence to this Condition object. if_branch and else_branch are the elements to @@ -66,7 +67,7 @@ class HardwareCondition(Condition): During the translation process, HardwareCondition instanced will produce in code blocks for branches/loop bodies and the corresponding conditional jump instructions. """ - def __init__(self, trigger: Trigger) -> None: + def __init__(self, trigger: instructions.Trigger) -> None: """Create a new HardwareCondition instance. Argument trigger is the trigger handle of the corresponding hardware device.""" super().__init__() self.__trigger = trigger # type: Trigger @@ -75,26 +76,26 @@ def requires_stop(self) -> bool: return False def build_sequence_loop(self, - delegator: SequencingElement, - body: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], + delegator: sequencing.SequencingElement, + body: sequencing.SequencingElement, + sequencer: sequencing.Sequencer, + parameters: Dict[str, parameters.Parameter], conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: + instruction_block: instructions.InstructionBlock) -> None: body_block = instruction_block.create_embedded_block() - body_block.return_ip = InstructionPointer(instruction_block, len(body_block)) + body_block.return_ip = instructions.InstructionPointer(instruction_block, len(body_block)) instruction_block.add_instruction_cjmp(self.__trigger, body_block) sequencer.push(body, parameters, conditions, body_block) - def build_sequence_branch(self, - delegator: SequencingElement, - if_branch: SequencingElement, - else_branch: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], + def build_sequence_branch(self, + delegator: sequencing.SequencingElement, + if_branch: sequencing.SequencingElement, + else_branch: sequencing.SequencingElement, + sequencer: sequencing.Sequencer, + parameters: Dict[str, parameters.Parameter], conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: + instruction_block: instructions.InstructionBlock) -> None: if_block = instruction_block.create_embedded_block() else_block = instruction_block.create_embedded_block() @@ -104,7 +105,7 @@ def build_sequence_branch(self, instruction_block.add_instruction_goto(else_block) sequencer.push(else_branch, parameters, conditions, else_block) - if_block.return_ip = InstructionPointer(instruction_block, len(instruction_block)) + if_block.return_ip = instructions.InstructionPointer(instruction_block, len(instruction_block)) else_block.return_ip = if_block.return_ip @@ -139,12 +140,12 @@ def requires_stop(self) -> bool: return evaluation_result is None def build_sequence_loop(self, - delegator: SequencingElement, - body: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], + delegator: sequencing.SequencingElement, + body: sequencing.SequencingElement, + sequencer: sequencing.Sequencer, + parameters: Dict[str, parameters.Parameter], conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: + instruction_block: instructions.InstructionBlock) -> None: evaluation_result = self.__callback(self.__loop_iteration) if evaluation_result is None: @@ -159,14 +160,14 @@ def build_sequence_loop(self, sequencer.push(body, parameters, conditions, instruction_block) self.__loop_iteration += 1 # next time, evaluate for next iteration - def build_sequence_branch(self, - delegator: SequencingElement, - if_branch: SequencingElement, - else_branch: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], + def build_sequence_branch(self, + delegator: sequencing.SequencingElement, + if_branch: sequencing.SequencingElement, + else_branch: sequencing.SequencingElement, + sequencer: sequencing.Sequencer, + parameters: Dict[str, parameters.Parameter], conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: + instruction_block: instructions.InstructionBlock) -> None: evaluation_result = self.__callback(self.__loop_iteration) if evaluation_result is None: @@ -182,45 +183,6 @@ def build_sequence_branch(self, sequencer.push(else_branch, parameters, conditions, instruction_block) -class ProxyCondition(Condition): - - def __init__(self, condition_name: str) -> None: - super().__init__() - self.__condition_name = condition_name - self.__condition = None # type: Condition - - def acquire_proxied(self, conditions: Dict[str, Condition]) -> None: - self.__condition = conditions[self.__condition_name] - - def requires_stop(self) -> bool: - if self.__condition is None: - raise Exception("The Condition reference '{}' has not been resolved.".format(self.__condition_name)) - return self.__condition.requires_stop() - - def build_sequence_loop(self, - delegator: SequencingElement, - body: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], - conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: - if self.__condition is None: - raise Exception("The Condition reference '{}' has not been resolved.".format(self.__condition_name)) - self.__condition.build_sequence_loop(delegator, body, sequencer, parameters, conditions, instruction_block) - - def build_sequence_branch(self, - delegator: SequencingElement, - if_branch: SequencingElement, - else_branch: SequencingElement, - sequencer: Sequencer, - parameters: Dict[str, Parameter], - conditions: Dict[str, 'Condition'], - instruction_block: InstructionBlock) -> None: - if self.__condition is None: - raise Exception("The Condition reference '{}' has not been resolved.".format(self.__condition_name)) - self.__condition.build_sequence_branch(delegator, if_branch, else_branch, sequencer, parameters, conditions, instruction_block) - - class ConditionEvaluationException(Exception): """Indicates that a SoftwareCondition cannot be evaluated yet.""" diff --git a/qctoolkit/pulses/function_pulse_template.py b/qctoolkit/pulses/function_pulse_template.py index cd6c58d79..e3de7b82b 100644 --- a/qctoolkit/pulses/function_pulse_template.py +++ b/qctoolkit/pulses/function_pulse_template.py @@ -10,11 +10,11 @@ from qctoolkit.expressions import Expression from qctoolkit.serialization import Serializer -from .parameters import ParameterDeclaration, Parameter -from .pulse_template import PulseTemplate, MeasurementWindow -from .sequencing import InstructionBlock, Sequencer -from .sequence_pulse_template import ParameterNotProvidedException -from .instructions import Waveform +from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter +from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.sequencing import InstructionBlock, Sequencer +from qctoolkit.pulses.sequence_pulse_template import ParameterNotProvidedException +from qctoolkit.pulses.instructions import Waveform logger = logging.getLogger(__name__) diff --git a/qctoolkit/pulses/instructions.py b/qctoolkit/pulses/instructions.py index ebd83ead6..c24f6ba97 100644 --- a/qctoolkit/pulses/instructions.py +++ b/qctoolkit/pulses/instructions.py @@ -7,7 +7,7 @@ """LOCAL IMPORTS""" from qctoolkit.comparable import Comparable -from .interpolation import InterpolationStrategy +from qctoolkit.pulses.interpolation import InterpolationStrategy # TODO lumip: add docstrings diff --git a/qctoolkit/pulses/loop_pulse_template.py b/qctoolkit/pulses/loop_pulse_template.py index 321a1b602..3b7cf96a5 100644 --- a/qctoolkit/pulses/loop_pulse_template.py +++ b/qctoolkit/pulses/loop_pulse_template.py @@ -3,13 +3,14 @@ """RELATED THIRD PARTY IMPORTS""" """LOCAL IMPORTS""" -from .parameters import Parameter -from .pulse_template import PulseTemplate, MeasurementWindow -from .conditions import Condition -from .instructions import InstructionBlock -from .sequencing import Sequencer from qctoolkit.serialization import Serializer +from qctoolkit.pulses.parameters import Parameter +from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.conditions import Condition +from qctoolkit.pulses.instructions import InstructionBlock +from qctoolkit.pulses.sequencing import Sequencer + __all__ = ['LoopPulseTemplate', 'ConditionMissingException'] diff --git a/qctoolkit/pulses/plotting.py b/qctoolkit/pulses/plotting.py index 705ec8034..b9014b89b 100644 --- a/qctoolkit/pulses/plotting.py +++ b/qctoolkit/pulses/plotting.py @@ -2,9 +2,9 @@ from matplotlib import pyplot as plt from typing import Dict, Tuple -from .parameters import Parameter -from .sequencing import Sequencer, SequencingElement -from .instructions import EXECInstruction, STOPInstruction, InstructionSequence +from qctoolkit.pulses.parameters import Parameter +from qctoolkit.pulses.sequencing import Sequencer, SequencingElement +from qctoolkit.pulses.instructions import EXECInstruction, STOPInstruction, InstructionSequence __all__ = ["Plotter", "plot", "PlottingNotPossibleException"] diff --git a/qctoolkit/pulses/pulse_template.py b/qctoolkit/pulses/pulse_template.py index bea3d3ae1..f266d854e 100644 --- a/qctoolkit/pulses/pulse_template.py +++ b/qctoolkit/pulses/pulse_template.py @@ -8,8 +8,8 @@ """LOCAL IMPORTS""" from qctoolkit.serialization import Serializable -from .parameters import ParameterDeclaration, Parameter -from .sequencing import SequencingElement +from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter +from qctoolkit.pulses.sequencing import SequencingElement logger = logging.getLogger(__name__) diff --git a/qctoolkit/pulses/repetition_pulse_template.py b/qctoolkit/pulses/repetition_pulse_template.py index 772c3074c..eab9752d3 100644 --- a/qctoolkit/pulses/repetition_pulse_template.py +++ b/qctoolkit/pulses/repetition_pulse_template.py @@ -2,11 +2,11 @@ from qctoolkit.serialization import Serializer -from .pulse_template import PulseTemplate, MeasurementWindow -from .sequencing import Sequencer -from .instructions import InstructionBlock -from .parameters import ParameterDeclaration, Parameter -from .conditions import Condition +from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.sequencing import Sequencer +from qctoolkit.pulses.instructions import InstructionBlock +from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter +from qctoolkit.pulses.conditions import Condition __all__ = ["RepetitionPulseTemplate", "ParameterNotIntegerException"] diff --git a/qctoolkit/pulses/sequence_pulse_template.py b/qctoolkit/pulses/sequence_pulse_template.py index 180df210d..1662ea8d4 100644 --- a/qctoolkit/pulses/sequence_pulse_template.py +++ b/qctoolkit/pulses/sequence_pulse_template.py @@ -6,10 +6,10 @@ from qctoolkit.serialization import Serializer from qctoolkit.expressions import Expression -from .pulse_template import PulseTemplate, MeasurementWindow -from .parameters import ParameterDeclaration, Parameter, ParameterNotProvidedException -from .sequencing import InstructionBlock, Sequencer -from .conditions import Condition +from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter, ParameterNotProvidedException +from qctoolkit.pulses.sequencing import InstructionBlock, Sequencer +from qctoolkit.pulses.conditions import Condition logger = logging.getLogger(__name__) @@ -106,7 +106,7 @@ def requires_stop(self, parameters: Dict[str, Parameter], conditions: Dict[str, def __map_parameter(self, mapping_function: str, parameters: Dict[str, Parameter]) -> Parameter: external_parameters = mapping_function.variables() - external_values = {name: float(parameters[name]) for name in external_parameters} + external_values = {name: parameters[name].get_value() for name in external_parameters} return mapping_function.evaluate(external_values) def build_sequence(self, diff --git a/qctoolkit/pulses/sequencing.py b/qctoolkit/pulses/sequencing.py index 6ee45af04..475da61e7 100644 --- a/qctoolkit/pulses/sequencing.py +++ b/qctoolkit/pulses/sequencing.py @@ -5,8 +5,8 @@ """RELATED THIRD PARTY IMPORTS""" """LOCAL IMPORTS""" -from .instructions import InstructionBlock -from .parameters import Parameter, ConstantParameter +from qctoolkit.pulses.instructions import InstructionBlock +from qctoolkit.pulses.parameters import Parameter, ConstantParameter __all__ = ["SequencingElement", "Sequencer"] diff --git a/qctoolkit/pulses/table_pulse_template.py b/qctoolkit/pulses/table_pulse_template.py index 3647eff65..777b67d63 100644 --- a/qctoolkit/pulses/table_pulse_template.py +++ b/qctoolkit/pulses/table_pulse_template.py @@ -10,12 +10,12 @@ """LOCAL IMPORTS""" from qctoolkit.serialization import Serializer -from .parameters import ParameterDeclaration, Parameter -from .pulse_template import PulseTemplate, MeasurementWindow -from .sequencing import InstructionBlock, Sequencer -from .interpolation import InterpolationStrategy, LinearInterpolationStrategy, HoldInterpolationStrategy, JumpInterpolationStrategy -from .instructions import Waveform, WaveformTable -from .conditions import Condition +from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter +from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.sequencing import InstructionBlock, Sequencer +from qctoolkit.pulses.interpolation import InterpolationStrategy, LinearInterpolationStrategy, HoldInterpolationStrategy, JumpInterpolationStrategy +from qctoolkit.pulses.instructions import Waveform, WaveformTable +from qctoolkit.pulses.conditions import Condition logger = logging.getLogger(__name__) From 79b3508f1d1d62e0c24e3b016301288d5da381f3 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 16 Nov 2015 12:43:25 +0100 Subject: [PATCH 02/33] Removed qctoolkit/main.py. --- qctoolkit/main.py | 4 ---- 1 file changed, 4 deletions(-) delete mode 100644 qctoolkit/main.py diff --git a/qctoolkit/main.py b/qctoolkit/main.py deleted file mode 100644 index e27600a2b..000000000 --- a/qctoolkit/main.py +++ /dev/null @@ -1,4 +0,0 @@ -from pulses import * - -if __name__ == '__main__': - pass \ No newline at end of file From 3c9dbacfa8372ff349fd8f9811baf1e191ac08ae Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 16 Nov 2015 13:09:42 +0100 Subject: [PATCH 03/33] Restructured the doc folder and added auto-generated API documentation. --- doc/Makefile | 52 ++++---- doc/make.bat | 1 + doc/source/concepts/concepts.rst | 2 + doc/source/conf.py | 1 + .../TablePulseTemplate_example.rst | 4 +- doc/source/examples/examples.rst | 5 + doc/source/index.rst | 9 +- doc/source/qctoolkit.hardware.rst | 18 +++ doc/source/qctoolkit.pulses.rst | 118 ++++++++++++++++++ doc/source/qctoolkit.qcmatlab.rst | 30 +++++ doc/source/qctoolkit.rst | 48 +++++++ doc/source/qctoolkit.utils.rst | 22 ++++ 12 files changed, 279 insertions(+), 31 deletions(-) create mode 100644 doc/source/concepts/concepts.rst rename doc/source/{ => examples}/TablePulseTemplate_example.rst (98%) create mode 100644 doc/source/examples/examples.rst create mode 100644 doc/source/qctoolkit.hardware.rst create mode 100644 doc/source/qctoolkit.pulses.rst create mode 100644 doc/source/qctoolkit.qcmatlab.rst create mode 100644 doc/source/qctoolkit.rst create mode 100644 doc/source/qctoolkit.utils.rst diff --git a/doc/Makefile b/doc/Makefile index 41189e805..34cd68009 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -6,6 +6,7 @@ SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build +SPHINXAPIDOC = sphinx-apidoc # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) @@ -51,38 +52,41 @@ help: clean: rm -rf $(BUILDDIR)/* -html: +extractapi: + $(SPHINXAPIDOC) --no-toc -o source ../qctoolkit + +html: extractapi $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." -dirhtml: +dirhtml: extractapi $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." -singlehtml: +singlehtml: extractapi $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." -pickle: +pickle: extractapi $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." -json: +json: extractapi $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." -htmlhelp: +htmlhelp: extractapi $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." -qthelp: +qthelp: extractapi $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ @@ -91,7 +95,7 @@ qthelp: @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/qc-toolkit.qhc" -applehelp: +applehelp: extractapi $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp @echo @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." @@ -99,7 +103,7 @@ applehelp: "~/Library/Documentation/Help or install it in your application" \ "bundle." -devhelp: +devhelp: extractapi $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @@ -108,85 +112,85 @@ devhelp: @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/qc-toolkit" @echo "# devhelp" -epub: +epub: extractapi $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." -latex: +latex: extractapi $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." -latexpdf: +latexpdf: extractapi $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -latexpdfja: +latexpdfja: extractapi $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." -text: +text: extractapi $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." -man: +man: extractapi $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." -texinfo: +texinfo: extractapi $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." -info: +info: extractapi $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." -gettext: +gettext: extractapi $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." -changes: +changes: extractapi $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." -linkcheck: +linkcheck: extractapi $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." -doctest: +doctest: extractapi $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." -coverage: +coverage: extractapi $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage @echo "Testing of coverage in the sources finished, look at the " \ "results in $(BUILDDIR)/coverage/python.txt." -xml: +xml: extractapi $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." -pseudoxml: +pseudoxml: extractapi $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." diff --git a/doc/make.bat b/doc/make.bat index d7d9e05d6..4c5f393ed 100644 --- a/doc/make.bat +++ b/doc/make.bat @@ -71,6 +71,7 @@ if errorlevel 9009 ( :sphinx_ok +sphinx-apidoc --no-toc -o source ../qctoolkit if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html diff --git a/doc/source/concepts/concepts.rst b/doc/source/concepts/concepts.rst new file mode 100644 index 000000000..a64d44ec6 --- /dev/null +++ b/doc/source/concepts/concepts.rst @@ -0,0 +1,2 @@ +Concepts +======== \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py index f7f1f3925..a37f0b0b6 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -39,6 +39,7 @@ 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', + 'sphinx.ext.autodoc' ] # Add any paths that contain templates here, relative to this directory. diff --git a/doc/source/TablePulseTemplate_example.rst b/doc/source/examples/TablePulseTemplate_example.rst similarity index 98% rename from doc/source/TablePulseTemplate_example.rst rename to doc/source/examples/TablePulseTemplate_example.rst index 5a896518a..3be995fe9 100644 --- a/doc/source/TablePulseTemplate_example.rst +++ b/doc/source/examples/TablePulseTemplate_example.rst @@ -5,8 +5,8 @@ Creating a New Pulse Template This example goes through the workflow of creating a new type of pulse from scratch using the `TablePulseTemplate` class. -.. figure:: _static/example_pulse.* - :width: 12cm +.. figure:: ../_static/example_pulse.svg + :width: 35% :align: center :alt: Example pulse diff --git a/doc/source/examples/examples.rst b/doc/source/examples/examples.rst new file mode 100644 index 000000000..029dbbbc4 --- /dev/null +++ b/doc/source/examples/examples.rst @@ -0,0 +1,5 @@ +Examples +======== + +.. toctree:: + TablePulseTemplate_example \ No newline at end of file diff --git a/doc/source/index.rst b/doc/source/index.rst index e51897e53..765fd3d7f 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -9,13 +9,12 @@ Welcome to qc-toolkit's documentation! Contents: .. toctree:: - :maxdepth: 2 + :maxdepth: 3 :numbered: - TablePulseTemplate_example - -.. automodule::pulses -.. automodule::utils + concepts/concepts + examples/examples + qctoolkit API Documentation Indices and tables ================== diff --git a/doc/source/qctoolkit.hardware.rst b/doc/source/qctoolkit.hardware.rst new file mode 100644 index 000000000..4326c5724 --- /dev/null +++ b/doc/source/qctoolkit.hardware.rst @@ -0,0 +1,18 @@ +qctoolkit.hardware package +========================== + +Subpackages +----------- + +.. toctree:: + + qctoolkit.hardware.awgs + qctoolkit.hardware.dacs + +Module contents +--------------- + +.. automodule:: qctoolkit.hardware + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/qctoolkit.pulses.rst b/doc/source/qctoolkit.pulses.rst new file mode 100644 index 000000000..724d80c7e --- /dev/null +++ b/doc/source/qctoolkit.pulses.rst @@ -0,0 +1,118 @@ +qctoolkit.pulses package +======================== + +Submodules +---------- + +qctoolkit.pulses.branch_pulse_template module +--------------------------------------------- + +.. automodule:: qctoolkit.pulses.branch_pulse_template + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.conditions module +---------------------------------- + +.. automodule:: qctoolkit.pulses.conditions + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.function_pulse_template module +----------------------------------------------- + +.. automodule:: qctoolkit.pulses.function_pulse_template + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.instructions module +------------------------------------ + +.. automodule:: qctoolkit.pulses.instructions + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.interpolation module +------------------------------------- + +.. automodule:: qctoolkit.pulses.interpolation + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.loop_pulse_template module +------------------------------------------- + +.. automodule:: qctoolkit.pulses.loop_pulse_template + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.parameters module +---------------------------------- + +.. automodule:: qctoolkit.pulses.parameters + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.plotting module +-------------------------------- + +.. automodule:: qctoolkit.pulses.plotting + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.pulse_template module +-------------------------------------- + +.. automodule:: qctoolkit.pulses.pulse_template + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.repetition_pulse_template module +------------------------------------------------- + +.. automodule:: qctoolkit.pulses.repetition_pulse_template + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.sequence_pulse_template module +----------------------------------------------- + +.. automodule:: qctoolkit.pulses.sequence_pulse_template + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.sequencing module +---------------------------------- + +.. automodule:: qctoolkit.pulses.sequencing + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.pulses.table_pulse_template module +-------------------------------------------- + +.. automodule:: qctoolkit.pulses.table_pulse_template + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: qctoolkit.pulses + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/qctoolkit.qcmatlab.rst b/doc/source/qctoolkit.qcmatlab.rst new file mode 100644 index 000000000..048718de7 --- /dev/null +++ b/doc/source/qctoolkit.qcmatlab.rst @@ -0,0 +1,30 @@ +qctoolkit.qcmatlab package +========================== + +Submodules +---------- + +qctoolkit.qcmatlab.manager module +--------------------------------- + +.. automodule:: qctoolkit.qcmatlab.manager + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.qcmatlab.pulse_control module +--------------------------------------- + +.. automodule:: qctoolkit.qcmatlab.pulse_control + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: qctoolkit.qcmatlab + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/qctoolkit.rst b/doc/source/qctoolkit.rst new file mode 100644 index 000000000..98f63f7e7 --- /dev/null +++ b/doc/source/qctoolkit.rst @@ -0,0 +1,48 @@ +qctoolkit package +================= + +Subpackages +----------- + +.. toctree:: + + qctoolkit.hardware + qctoolkit.pulses + qctoolkit.qcmatlab + qctoolkit.utils + +Submodules +---------- + +qctoolkit.comparable module +--------------------------- + +.. automodule:: qctoolkit.comparable + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.expressions module +---------------------------- + +.. automodule:: qctoolkit.expressions + :members: + :undoc-members: + :show-inheritance: + +qctoolkit.serialization module +------------------------------ + +.. automodule:: qctoolkit.serialization + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: qctoolkit + :members: + :undoc-members: + :show-inheritance: diff --git a/doc/source/qctoolkit.utils.rst b/doc/source/qctoolkit.utils.rst new file mode 100644 index 000000000..85e92b026 --- /dev/null +++ b/doc/source/qctoolkit.utils.rst @@ -0,0 +1,22 @@ +qctoolkit.utils package +======================= + +Submodules +---------- + +qctoolkit.utils.type_check module +--------------------------------- + +.. automodule:: qctoolkit.utils.type_check + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: qctoolkit.utils + :members: + :undoc-members: + :show-inheritance: From 0a2d536839bd7deef6e3c208ad42b64f747fb182 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 23 Nov 2015 16:06:19 +0100 Subject: [PATCH 04/33] [wip] Added documentation for fundamental concepts. --- doc/source/concepts/branching.rst | 4 +++ doc/source/concepts/concepts.rst | 10 +++++- doc/source/concepts/pulsetemplates.rst | 26 ++++++++++++++ doc/source/concepts/sequencing.rst | 17 +++++++++ doc/source/concepts/serialization.rst | 49 ++++++++++++++++++++++++++ 5 files changed, 105 insertions(+), 1 deletion(-) create mode 100644 doc/source/concepts/branching.rst create mode 100644 doc/source/concepts/pulsetemplates.rst create mode 100644 doc/source/concepts/sequencing.rst create mode 100644 doc/source/concepts/serialization.rst diff --git a/doc/source/concepts/branching.rst b/doc/source/concepts/branching.rst new file mode 100644 index 000000000..af6748ea4 --- /dev/null +++ b/doc/source/concepts/branching.rst @@ -0,0 +1,4 @@ +.. _branching: + +Conditional Branching +--------------------- \ No newline at end of file diff --git a/doc/source/concepts/concepts.rst b/doc/source/concepts/concepts.rst index a64d44ec6..18ae3671b 100644 --- a/doc/source/concepts/concepts.rst +++ b/doc/source/concepts/concepts.rst @@ -1,2 +1,10 @@ Concepts -======== \ No newline at end of file +======== + +This section will explain the fundamental design concepts of the qctoolkit. + +.. toctree:: + pulsetemplates + serialization + sequencing + branching \ No newline at end of file diff --git a/doc/source/concepts/pulsetemplates.rst b/doc/source/concepts/pulsetemplates.rst new file mode 100644 index 000000000..030efd6a7 --- /dev/null +++ b/doc/source/concepts/pulsetemplates.rst @@ -0,0 +1,26 @@ +.. _pulsetemplates: + +Pulse Templates +--------------- + +The qctoolkit represents pulses as abstract pulse templates. A pulse template can be understood as a class of pulses that share a similar structure but differ in the concrete amplitude or duration of voltage levels. To this end, pulse templates are parametrizable. Pulse templates are also designed to feature easy reusability of existing templates and conditional execution based on hardware triggers, if supported by the devices. + +There are 6 types of different pulse template classes, briefly explained in the following. :class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` are used to define the atomic building blocks of pulses in the following ways: :class:`.TablePulseTemplate` allows the user to specify pairs of time and voltage values and choose an interpolation strategy between neighbouring points. :class:`.FunctionPulseTemplate` will accept any mathematical function that maps time to voltage values. All other pulse template variants are then used to construct arbitrarily complex pulses by combining existing ones into new structures: :class:`.SequencePulseTemplate` enables the user to specify a sequence of existing pulse templates (subtemplates) and modify parameter values using a mapping function. :class:`.RepetitionPulseTemplate` is used to simply repeat one existing pulse template a given (constant) number of times. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` implement conditional execution if supported. All of these pulse template variants can be similarly accessed through the common interface declared by :class:`.PulseTemplate`. [#tree]_ [#pattern]_ + +Each pulse template can be stored persistently in a human-readable JSON file. :ref:`Read more about serialization `. + +Parameters +^^^^^^^^^^ + +As mentioned above, all pulse templates may contain parameters. :class:`.TablePulseTemplate` allows parameter references as table entries on the time and voltage domain. These are represented as :class:`.ParameterDeclaration` objects which are identified by a unique name and can impose lower and upper boundaries to the expected parameter value as well as a default value. :class:`.SequencePulseTemplate` allows to specify a set of new parameter declarations and a mapping of these to the parameter declarations of its subtemplates. This allows renaming of parameters, e.g., to avoid name clashes if several subtemplates declare similarly named parameters. The mapping also allows mathematical transformation of parameter values, such that values that are passed to subtemplates can be obtained by deriving them from one or more other parameter values passed to the :class:`.SequencePulseTemplate`. :class:`.RepetitionPulseTemplate`, :class:`.LoopPulseTemplate` and :class:`BranchPulseTemplate` will simply pass parameters to their subtemplates without modifying them in any way. + +The mathematical expressions (for parameter transformation or as the function of the :class:`.FunctionPulseTemplate`) are encapsulated into an :class:`.Expression` class which wraps existing python packages that are able to parse and evaluate expressions given as strings such as `py_expression_eval `_ and `numexpr `_. + +Obtaining a Concrete Pulse +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +To obtain a pulse ready for execution on the hardware from a pulse template, the user has to specify parameter values (if parameters were used in the pulse templates in question). In the simplest case, parameters are constant values that can be provided as plain float values. Other cases may require parameter values to be computed based on some measurement values obtained during preceding executions. If so, a subclass of the :class:`.Parameter` class which performs this computations when queried for a value can be provided. To translates the object structures that encode the pulse template in the software into a sequential representation of the concrete pulse with the given parameter values that is understandable by the hardware, the sequencing process has to be invoked. During this process, all parameter values are checked for consistency with the boundaries declared by the parameter declarations and the process is aborted if any violation occurs. :ref:`Read more about the sequencing process `. + +.. rubric:: Footnotes +.. [#tree] Regarded as objects in the programming language, each pulse template is a tree of PulseTemplate objects, where the atomic templates (:class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects) are the leafs while the remaining ones form the inner nodes of the tree. +.. [#pattern] The design of the pulse template class hierarchy is an application of the `Composite Pattern `_. \ No newline at end of file diff --git a/doc/source/concepts/sequencing.rst b/doc/source/concepts/sequencing.rst new file mode 100644 index 000000000..b103aa556 --- /dev/null +++ b/doc/source/concepts/sequencing.rst @@ -0,0 +1,17 @@ +.. _sequencing: + +Sequencing +---------- + +Using the :ref:`pulse template definition class structures ` yields a tree structure of :class:`.PulseTemplate` objects. To obtain a concrete pulse that can be executed, parameters have to be replaced by corresponding values and the object structure has to be converted into a sequence of waveforms (and possibly triggered jump annotations) that the hardware drivers can comprehend. This process is called *sequencing* in the qctoolkit. It converts :class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects into a waveform representation by sampling voltage values along the time domain using the specified interpolation rules between table values or evaluating the defining function respectively. The tree structure arising from the use of :class:`.SequencePulseTemplate`, :class:`.RepetitionPulseTemplate`, :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` is converted into an intermediate instruction language consisting of four instructions: Execute a waveform (:class:`.EXECInstruction`), an unconditional goto to another instruction (:class:`.GOTOInstruction`), a conditional jump to another instruction (:class:`.JMPInstruction`) and a stop command, halting execution (:class:`.STOPInstruction`). + +This approach was inspired by translation of syntax trees to machine instructions in modern compilers and necessitated by the fact that the hardware requires sequential commands rather than convoluted object structures. The output of the sequencing process is a set of waveforms and a sequence of instructions. These will later be interpreted by hardware drivers which will configure the specific devices accordingly (assuming these are capable of the required functionality). If :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` are not used, the compiled instruction sequence will consist only of execution instructions followed by a stop instruction, which represents a simple sequence of waveforms to play back. + +The sequencing process is performed by a :class:`.Sequencer` and started with a call to :meth:`.Sequencer.build`. :class:`.Sequencer` maintains a stack of :class:`.SequencingElement` objects (i.e. pulse templates) that still need to be translated. Pushing a pulse template to the stack using :meth:`.Sequencer.push` will cause :class:`.Sequencer` to translate it next. Translation works as follows: :class:`.Sequencer` pops the first element from the stack and calls its :meth:`.SequencingElement.build_sequence` method. In the case of a :class:`.TablePulseTemplate`, this adds an :class:`.EXECInstruction` referring to a :class:`.TableWaveform` to the instruction sequence. In the case of a :class:`.SequencePulseTemplate`, this simply adds all subtemplates to the sequencing stack such that they are translated next. :class:`.FunctionPulseTemplate` and :class:`.RepetitionPulseTemplate` act very similarly. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` behave in a more complicated way due to their branching ability. :ref:`Read more on conditional branching `. + +The sequencing process can be interrupted at any point, e.g., if some parameter value depends on measurements that are to be made in the preceding part of the pulse. In this case, the method :meth:`.SequencingElement.requires_stop` of the first stack element will return `true`. :class:`.Sequencer` then stops the translation and returns the instruction sequence generated so far. This can then be executed and measurement can be made. Afterwards, the sequencing process can be invoked again. :class:`.Sequencer` will resume where it was interrupted previously (with the first item that remained on the stack). :meth:`.Sequencer.has_finished` allows to check, whether the sequencing process was completed. + +Sequencing Process Example +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. note:: Provide an exemplary sequencing run \ No newline at end of file diff --git a/doc/source/concepts/serialization.rst b/doc/source/concepts/serialization.rst new file mode 100644 index 000000000..374c63ca2 --- /dev/null +++ b/doc/source/concepts/serialization.rst @@ -0,0 +1,49 @@ +.. _serialization: + +Serialization +------------- +Serialization and deserilization mechanisms were implemented to enable persistent storage and thus reusability of pulse template definitions. Currently, the serialization format is a plain text document containing JSON formatted data. [#format]_ + +Serialization was constructed in a way that allows that a given pulse template may refer to subtemplates which are used by several different parent templates (or more than once in one) such as, e.g., the measurement pulse. These should then be stored in a separate file and referenced by a unique identifier in all parent templates to avoid unnecessary redundancy. On the other hand, there might be subtemplates which are only relevant to their parent and thus should be embedded in its serialization to avoid creating a multitude of files that are meaningless to a user. To allow the serialization process to make this distinction, each pulse template (or other serializable object) provides an optional identifier (which can be set by the user via the constructor for all pulse template variants). If an identifier is present in a pulse template, it is stored in a separate file. If not, it is embedded in its parent's serialization. + +The implementation of (de)serialization features :class:`.Serializer` class and a :class:`.Serializable` interface. Every class that implements the latter can be serialized and thus stored as a JSON file. Currently, this is the case for all :class:`.PulseTemplate` variants as well as the :class:`.ParameterDeclaration` class. Additionally, the :class:`.StorageBackend` interface abstracts the actual storage backend. While currently there only exists a single implementation of this interface, namely the :class:`.FileSystemStorageBackend`, this allows to support, e.g., database storage, in the future. + +The essential methods of :class:`.Serializer` are :meth:`.Serializer.serialize` and :meth:`.Serializer.deserialize`. :meth:`.Serializer.serialize` serializes a serializable object (i.e., any object of a class that implements/derives from :class:`.Serializable`) in a recursive process: It invokes the :meth:`.Serializable.get_serialization_data` method of the provided serializable object, which in turn might invoke the :class:`.Sequencer` to obtain a serialization for complex embedded data (such as a :class:`.ParameterDeclaration` in a :class:`.TablePulseTemplate`). In the end, a dictionary representation of the object is obtained which is then converted into a JSON string using built-in Python functionality. The JSON representation is finally stored using a given :class:`.StorageBackend`. Deserialization (:meth:`.Serializer.deserialize`) works analogously and is thus not explained in detail here. + +For an example of how to use serialization to store and load pulse templates, see . + +.. note:: write examples + +Implementing a :class:`.Serializable` Class +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +To make any new class serializable, it must derive from the :class:`.Serializable` and implement the methods :meth:`.Serializable.get_serialization_data`, :meth:`.Serializable.deserialize` and the :attr:`.Serializable.identifier` property. + +If class objects should be stored in a separate file, the `identifier` must be a non-empty string. If, on the other hand, class object should be embedded into their parent's serialization (as is the case for, e.g., :class:`.ParameterDeclaration`), must be `None`. + +The method `serialize` should return a dictionary of native Python types containing all relevant data. If the class has members that are not native Python types but must be serialized, the must be serializable and the `serialize` method can obtain their serialization by calling :meth:`.Serializer._serialize_subpulse` and then embed this in its result. `serialize` should not include the identifier in the returned dictionary. + +The method `deserialize` is invoked with all key-value pairs created by a call to `serialize` as keyword arguments as well as an additional `identifier` keyword argument (which may be `None`) and must return a valid corresponding class instance. + +The following may serve as a simple example: +:: + class Foo(Serializable): + + def __init__(self, template: PulseTemplate, identifier: Optional[str]=None) -> None: + self.__template = template + self.__identifier = identifier + + @property + def identifier(self) -> Optional[str]: + return self.__identifier + + def get_serialization_data(self, serializer: Serializer) -> Dict[str, Any]: + return dict(template=serializer._serialize_subpulse(self.__template)) + + @staticmethod + def deserialize(serializer: Serializer, template: Dict[str, Any], identifer: Optional[str]=None) -> Serializable: + return Foo(serialzer.deserialize(template), identifier=identifier) + + +.. rubric:: Footnotes + +.. [#format] After some discussion of the format in which to store the data, JSON files were the favored solution. The main competitor were relational SQL databases, which could provide a central, globally accessible pulse database. However, since pulses are often changed between experiments, a more flexible solution that can be maintained by users without database experience and also allows changes only in a local environment was desired. Storing pulse templates in files was the obvious solution to this. This greatest-simplicity-requirement was also imposed on the data format, which thus resulted in JSON being chosen over XML or other similar formats. An additional favorable argument for JSON is the fact that Python already provides methods that convert dictionaries containing only native python types into valid JSON and back. \ No newline at end of file From 34b6771389f5c3a5dae2802a11739dbe12412173 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 7 Dec 2015 13:57:46 +0100 Subject: [PATCH 05/33] Added documentation of branching concepts. --- doc/source/concepts/branching.rst | 16 +++++++++++++++- doc/source/concepts/sequencing.rst | 2 +- doc/source/concepts/serialization.rst | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/doc/source/concepts/branching.rst b/doc/source/concepts/branching.rst index af6748ea4..ef79dd8a0 100644 --- a/doc/source/concepts/branching.rst +++ b/doc/source/concepts/branching.rst @@ -1,4 +1,18 @@ .. _branching: Conditional Branching ---------------------- \ No newline at end of file +--------------------- + +The qctoolkit was designed to model conditional branching in pulse execution using the classes :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` of the :ref:`pulse template definition classes `. The software is intended to support use of trigger-based hardware jumps between waveforms as well as software-based evaluation of branching conditions, if the hardware does not support triggers or highly sophisticated evaluation of measured data is required. These options are represented as instances of the :class:`.Condition` class: :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` both contain unique identifiers (chosen by the user) of a condition. In the beginning of the :ref:`sequencing process `, the user provides a dictionary of :class:`.Condition` instances which are used to determine how the conditions for each template are evaluated. Currently, two different subclasses of :class:`.Condition` exist: :class:`.SoftwareCondition` represents a software-evaluated condition and accepts a function reference to any evaluation function (which must return None, if it cannot yet be evaluated, or a boolean value); :class:`.HardwareCondition` represents trigger-based hardware evaluation and basically stores a reference to a trigger which will later be evaluated by the specific hardware driver to set up the device accordingly. Note that software-based evaluation will interrupt the sequencing process and thus the execution of the pulse, if the evaluation cannot be performed during the sequencing run, e.g., if the evaluation of the condition is based on measurement data made during pulse execution. In this case, the pulse instruction sequence is only generated up to the branching and must be re-invoked later on, after executing this first part and obtaining the required data. Software-based evaluation is thus not applicable when high performance is required. + +Sequencing of Conditional Branching +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware never knows of the other path). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the caveat of being not real-time capable (as explained above). + +A note on implementation: The abstract :class:`.Condition` class defines an methods for generating sequences for branches or loops and to query if the condition can be evaluated. These are implemented by :class:`.SoftwareCondition` and :class:`.HardwareCondition` in the ways mentioned above. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` make use of the respective methods in their :meth:`.SequencingElement.build_sequence` method to defer sequence construction to the condition. Thus, during the sequencing process, the :class:`.Sequencer` calls :meth:`.SequencingElement.build_sequence` on the template which in turn invokes :meth:`.Condition.build_sequence_branch` or :meth:`.Condition.build_sequence_loop`. These then perform the actual sequence generation. These indirections allow for each class to act independently of the exact combination of if-else-branching versus looping and software- or hardware-based evaluation. + +Future Work +^^^^^^^^^^^ +Currently, there is no detailed concept on hardware abstraction and thus no meaningful representation of triggers and no hardware driver implementation that configures any device. This is still an open task. + +It is quite common for hardware to allow triggers to be not only a boolean signal but, e.g., any 8-bit signal, thus enabling more than two branches. While this should still be covered by the current classes by nesting :class:`.BranchPulseTemplate`s and configuring triggers appropriately, the implementation of a template class which acts like a C-style switch statement might be a worthwhile consideration. \ No newline at end of file diff --git a/doc/source/concepts/sequencing.rst b/doc/source/concepts/sequencing.rst index b103aa556..6eabea92d 100644 --- a/doc/source/concepts/sequencing.rst +++ b/doc/source/concepts/sequencing.rst @@ -3,7 +3,7 @@ Sequencing ---------- -Using the :ref:`pulse template definition class structures ` yields a tree structure of :class:`.PulseTemplate` objects. To obtain a concrete pulse that can be executed, parameters have to be replaced by corresponding values and the object structure has to be converted into a sequence of waveforms (and possibly triggered jump annotations) that the hardware drivers can comprehend. This process is called *sequencing* in the qctoolkit. It converts :class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects into a waveform representation by sampling voltage values along the time domain using the specified interpolation rules between table values or evaluating the defining function respectively. The tree structure arising from the use of :class:`.SequencePulseTemplate`, :class:`.RepetitionPulseTemplate`, :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` is converted into an intermediate instruction language consisting of four instructions: Execute a waveform (:class:`.EXECInstruction`), an unconditional goto to another instruction (:class:`.GOTOInstruction`), a conditional jump to another instruction (:class:`.JMPInstruction`) and a stop command, halting execution (:class:`.STOPInstruction`). +Defining pulses using the :ref:`pulse template definition class structures ` yields a tree structure of :class:`.PulseTemplate` objects. To obtain a concrete pulse that can be executed, parameters have to be replaced by corresponding values and the object structure has to be converted into a sequence of waveforms (and possibly triggered jump annotations) that the hardware drivers can comprehend. This process is called *sequencing* in the qctoolkit. It converts :class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects into a waveform representation by sampling voltage values along the time domain using the specified interpolation rules between table values or evaluating the defining function respectively. The tree structure arising from the use of :class:`.SequencePulseTemplate`, :class:`.RepetitionPulseTemplate`, :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` is converted into an intermediate instruction language consisting of four instructions: Execute a waveform (:class:`.EXECInstruction`), an unconditional goto to another instruction (:class:`.GOTOInstruction`), a conditional jump to another instruction (:class:`.JMPInstruction`) and a stop command, halting execution (:class:`.STOPInstruction`). This approach was inspired by translation of syntax trees to machine instructions in modern compilers and necessitated by the fact that the hardware requires sequential commands rather than convoluted object structures. The output of the sequencing process is a set of waveforms and a sequence of instructions. These will later be interpreted by hardware drivers which will configure the specific devices accordingly (assuming these are capable of the required functionality). If :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` are not used, the compiled instruction sequence will consist only of execution instructions followed by a stop instruction, which represents a simple sequence of waveforms to play back. diff --git a/doc/source/concepts/serialization.rst b/doc/source/concepts/serialization.rst index 374c63ca2..5a515fa83 100644 --- a/doc/source/concepts/serialization.rst +++ b/doc/source/concepts/serialization.rst @@ -20,7 +20,7 @@ To make any new class serializable, it must derive from the :class:`.Serializabl If class objects should be stored in a separate file, the `identifier` must be a non-empty string. If, on the other hand, class object should be embedded into their parent's serialization (as is the case for, e.g., :class:`.ParameterDeclaration`), must be `None`. -The method `serialize` should return a dictionary of native Python types containing all relevant data. If the class has members that are not native Python types but must be serialized, the must be serializable and the `serialize` method can obtain their serialization by calling :meth:`.Serializer._serialize_subpulse` and then embed this in its result. `serialize` should not include the identifier in the returned dictionary. +The method `serialize` should return a dictionary of native Python types containing all relevant data. If the class has members that are not native Python types but must be serialized, they must be serializable and the `serialize` method can obtain their serialization as the return value of :meth:`.Serializer._serialize_subpulse` and embed it in its result. The dictionary returned by `serialize` should not include the identifier in the returned dictionary. The method `deserialize` is invoked with all key-value pairs created by a call to `serialize` as keyword arguments as well as an additional `identifier` keyword argument (which may be `None`) and must return a valid corresponding class instance. From 1c231cd0c6e38259bd45e86de028ad96dd594478 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 7 Dec 2015 13:59:15 +0100 Subject: [PATCH 06/33] FileEntry type definition is now private in Serializer. --- qctoolkit/serialization.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/qctoolkit/serialization.py b/qctoolkit/serialization.py index 391f2d3bb..a0d4d05f7 100644 --- a/qctoolkit/serialization.py +++ b/qctoolkit/serialization.py @@ -89,10 +89,10 @@ def deserialize(serializer: 'Serializer', **kwargs) -> 'Serializable': class Serializer(object): - FileEntry = NamedTuple("FileEntry", [('serialization', str), ('serializable', Serializable)]) + __FileEntry = NamedTuple("FileEntry", [('serialization', str), ('serializable', Serializable)]) def __init__(self, storage_backend: StorageBackend) -> None: - self.__subpulses = dict() # type: Dict[str, Serializer.FileEntry] + self.__subpulses = dict() # type: Dict[str, Serializer.__FileEntry] self.__storage_backend = storage_backend def _serialize_subpulse(self, serializable: Serializable) -> Union[str, Dict[str, Any]]: @@ -105,7 +105,7 @@ def _serialize_subpulse(self, serializable: Serializable) -> Union[str, Dict[str if self.__subpulses[identifier].serializable is not serializable: raise Exception("Identifier '{}' assigned twice.".format(identifier)) else: - self.__subpulses[identifier] = Serializer.FileEntry(repr_, serializable) + self.__subpulses[identifier] = Serializer.__FileEntry(repr_, serializable) return identifier def dictify(self, serializable: Serializable) -> Dict[str, Dict[str, Any]]: From af60b5fb4962ecafaa87eebd340127f9b6254776 Mon Sep 17 00:00:00 2001 From: Eugen Kammerloher Date: Mon, 7 Dec 2015 16:35:07 +0100 Subject: [PATCH 07/33] Typo --- doc/source/concepts/pulsetemplates.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/concepts/pulsetemplates.rst b/doc/source/concepts/pulsetemplates.rst index 030efd6a7..05a9084cf 100644 --- a/doc/source/concepts/pulsetemplates.rst +++ b/doc/source/concepts/pulsetemplates.rst @@ -19,8 +19,8 @@ The mathematical expressions (for parameter transformation or as the function of Obtaining a Concrete Pulse ^^^^^^^^^^^^^^^^^^^^^^^^^^ -To obtain a pulse ready for execution on the hardware from a pulse template, the user has to specify parameter values (if parameters were used in the pulse templates in question). In the simplest case, parameters are constant values that can be provided as plain float values. Other cases may require parameter values to be computed based on some measurement values obtained during preceding executions. If so, a subclass of the :class:`.Parameter` class which performs this computations when queried for a value can be provided. To translates the object structures that encode the pulse template in the software into a sequential representation of the concrete pulse with the given parameter values that is understandable by the hardware, the sequencing process has to be invoked. During this process, all parameter values are checked for consistency with the boundaries declared by the parameter declarations and the process is aborted if any violation occurs. :ref:`Read more about the sequencing process `. +To obtain a pulse ready for execution on the hardware from a pulse template, the user has to specify parameter values (if parameters were used in the pulse templates in question). In the simplest case, parameters are constant values that can be provided as plain float values. Other cases may require parameter values to be computed based on some measurement values obtained during preceding executions. If so, a subclass of the :class:`.Parameter` class which performs this computations when queried for a value can be provided. In order to translate the object structures that encode the pulse template in the software into a sequential representation of the concrete pulse with the given parameter values that is understandable by the hardware, the sequencing process has to be invoked. During this process, all parameter values are checked for consistency with the boundaries declared by the parameter declarations and the process is aborted if any violation occurs. :ref:`Read more about the sequencing process `. .. rubric:: Footnotes .. [#tree] Regarded as objects in the programming language, each pulse template is a tree of PulseTemplate objects, where the atomic templates (:class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects) are the leafs while the remaining ones form the inner nodes of the tree. -.. [#pattern] The design of the pulse template class hierarchy is an application of the `Composite Pattern `_. \ No newline at end of file +.. [#pattern] The design of the pulse template class hierarchy is an application of the `Composite Pattern `_. From af55da9608601a7e864f98e7996f67d407cdee8f Mon Sep 17 00:00:00 2001 From: Eugen Kammerloher Date: Mon, 7 Dec 2015 16:50:11 +0100 Subject: [PATCH 08/33] Typo --- doc/source/concepts/serialization.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/source/concepts/serialization.rst b/doc/source/concepts/serialization.rst index 5a515fa83..be930415c 100644 --- a/doc/source/concepts/serialization.rst +++ b/doc/source/concepts/serialization.rst @@ -18,7 +18,7 @@ Implementing a :class:`.Serializable` Class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ To make any new class serializable, it must derive from the :class:`.Serializable` and implement the methods :meth:`.Serializable.get_serialization_data`, :meth:`.Serializable.deserialize` and the :attr:`.Serializable.identifier` property. -If class objects should be stored in a separate file, the `identifier` must be a non-empty string. If, on the other hand, class object should be embedded into their parent's serialization (as is the case for, e.g., :class:`.ParameterDeclaration`), must be `None`. +If class objects should be stored in a separate file, the `identifier` must be a non-empty string. If, on the other hand, class objects should be embedded into their parent's serialization (as is the case for, e.g., :class:`.ParameterDeclaration`), `identifier` must be `None`. The method `serialize` should return a dictionary of native Python types containing all relevant data. If the class has members that are not native Python types but must be serialized, they must be serializable and the `serialize` method can obtain their serialization as the return value of :meth:`.Serializer._serialize_subpulse` and embed it in its result. The dictionary returned by `serialize` should not include the identifier in the returned dictionary. @@ -46,4 +46,4 @@ The following may serve as a simple example: .. rubric:: Footnotes -.. [#format] After some discussion of the format in which to store the data, JSON files were the favored solution. The main competitor were relational SQL databases, which could provide a central, globally accessible pulse database. However, since pulses are often changed between experiments, a more flexible solution that can be maintained by users without database experience and also allows changes only in a local environment was desired. Storing pulse templates in files was the obvious solution to this. This greatest-simplicity-requirement was also imposed on the data format, which thus resulted in JSON being chosen over XML or other similar formats. An additional favorable argument for JSON is the fact that Python already provides methods that convert dictionaries containing only native python types into valid JSON and back. \ No newline at end of file +.. [#format] After some discussion of the format in which to store the data, JSON files were the favored solution. The main competitor were relational SQL databases, which could provide a central, globally accessible pulse database. However, since pulses are often changed between experiments, a more flexible solution that can be maintained by users without database experience and also allows changes only in a local environment was desired. Storing pulse templates in files was the obvious solution to this. This greatest-simplicity-requirement was also imposed on the data format, which thus resulted in JSON being chosen over XML or other similar formats. An additional favorable argument for JSON is the fact that Python already provides methods that convert dictionaries containing only native python types into valid JSON and back. From 5e61776f6927a9fd2a11e0950beb55c71f073777 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 7 Dec 2015 17:40:17 +0100 Subject: [PATCH 09/33] Added import for implementation example in serialization concept document. --- doc/source/concepts/serialization.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/doc/source/concepts/serialization.rst b/doc/source/concepts/serialization.rst index be930415c..85ba685ae 100644 --- a/doc/source/concepts/serialization.rst +++ b/doc/source/concepts/serialization.rst @@ -26,6 +26,10 @@ The method `deserialize` is invoked with all key-value pairs created by a call t The following may serve as a simple example: :: + from qctoolkit.serialization import Serializable, Serializer + from qctoolkit.pulses import PulseTemplate + from typing import Any, Dict, Optional + class Foo(Serializable): def __init__(self, template: PulseTemplate, identifier: Optional[str]=None) -> None: From a839b489333a2ad02222a1ee0109bbdb87837da4 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 7 Dec 2015 17:41:38 +0100 Subject: [PATCH 10/33] Some tests (not enough!!) and fixes for SequencePulseTemplate sequencing methods. --- qctoolkit/pulses/sequence_pulse_template.py | 22 +++---- tests/expression_tests.py | 15 +++++ tests/pulses/sequence_pulse_template_tests.py | 63 ++++++++++++++++++- 3 files changed, 86 insertions(+), 14 deletions(-) create mode 100644 tests/expression_tests.py diff --git a/qctoolkit/pulses/sequence_pulse_template.py b/qctoolkit/pulses/sequence_pulse_template.py index 1662ea8d4..251182b07 100644 --- a/qctoolkit/pulses/sequence_pulse_template.py +++ b/qctoolkit/pulses/sequence_pulse_template.py @@ -7,7 +7,7 @@ from qctoolkit.expressions import Expression from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow -from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter, ParameterNotProvidedException +from qctoolkit.pulses.parameters import ParameterDeclaration, Parameter, ParameterNotProvidedException, ConstantParameter from qctoolkit.pulses.sequencing import InstructionBlock, Sequencer from qctoolkit.pulses.conditions import Condition @@ -93,21 +93,20 @@ def requires_stop(self, parameters: Dict[str, Parameter], conditions: Dict[str, if not self.subtemplates: return False - # obtain first subtemplate - (template, mapping_functions) = self.subtemplates[0] - - # collect all parameters required to compute the mappings for the first subtemplate + # collect all parameters required to compute the mappings for the subtemplates external_parameters = set() - for mapping_function in mapping_functions.values(): - external_parameters = external_parameters | set(mapping_function.variables()) + for (template, mapping_functions) in self.subtemplates: + for mapping_function in mapping_functions.values(): + external_parameters = external_parameters | \ + {parameters[parameter_name] for parameter_name in mapping_function.variables()} # return True only if none of these requires a stop return any([p.requires_stop for p in external_parameters]) - def __map_parameter(self, mapping_function: str, parameters: Dict[str, Parameter]) -> Parameter: + def __map_parameter(self, mapping_function: Expression, parameters: Dict[str, Parameter]) -> Parameter: external_parameters = mapping_function.variables() external_values = {name: parameters[name].get_value() for name in external_parameters} - return mapping_function.evaluate(external_values) + return mapping_function.evaluate(**external_values) def build_sequence(self, sequencer: Sequencer, @@ -121,8 +120,9 @@ def build_sequence(self, # push subtemplates to sequencing stack with mapped parameters for template, mappings in reversed(self.subtemplates): - inner_parameters = {name: self.__map_parameter(mapping_function, parameters) for (name, mapping_function) in mappings.items()} - sequencer.push(template, inner_parameters, instruction_block) + inner_parameters = {name: ConstantParameter(self.__map_parameter(mapping_function, parameters)) + for (name, mapping_function) in mappings.items()} + sequencer.push(template, inner_parameters, conditions, instruction_block) def get_serialization_data(self, serializer: Serializer) -> Dict[str, Any]: data = dict() diff --git a/tests/expression_tests.py b/tests/expression_tests.py new file mode 100644 index 000000000..0e0adfa2e --- /dev/null +++ b/tests/expression_tests.py @@ -0,0 +1,15 @@ +import unittest + +from qctoolkit.expressions import Expression + + +class ExpressionTests(unittest.TestCase): + + def test_evaluate(self) -> None: + e = Expression('a * b + c') + params = { + 'a': 2, + 'b': 1.5, + 'c': -7 + } + self.assertEqual(2*1.5 - 7, e.evaluate(**params)) \ No newline at end of file diff --git a/tests/pulses/sequence_pulse_template_tests.py b/tests/pulses/sequence_pulse_template_tests.py index 26cf67ae0..dbbdc1d18 100644 --- a/tests/pulses/sequence_pulse_template_tests.py +++ b/tests/pulses/sequence_pulse_template_tests.py @@ -5,7 +5,7 @@ from qctoolkit.pulses.sequence_pulse_template import SequencePulseTemplate, MissingMappingException, UnnecessaryMappingException, MissingParameterDeclarationException from qctoolkit.pulses.parameters import ParameterDeclaration, ParameterNotProvidedException, ConstantParameter -from tests.pulses.sequencing_dummies import DummySequencer, DummyInstructionBlock +from tests.pulses.sequencing_dummies import DummySequencer, DummyInstructionBlock, DummyPulseTemplate, DummyParameter from tests.serialization_dummies import DummySerializer @@ -127,12 +127,26 @@ def test_missing_parameter(self): self.sequence.build_sequence(sequencer, parameters, {}, block) def test_build_sequence(self) -> None: - pass + subtemplate = DummyPulseTemplate(parameter_names={'hugo'}) + sequence = SequencePulseTemplate([(subtemplate, {'hugo': 'foo'}), + (subtemplate, {'hugo': 'bar'})], + {'foo', 'bar'}) + params = { + 'foo': DummyParameter(requires_stop=False), + 'bar': DummyParameter(requires_stop=False) + } + self.assertFalse(sequence.requires_stop(params, {})) + + params = { + 'foo': DummyParameter(requires_stop=False), + 'bar': DummyParameter(requires_stop=True) + } + self.assertTrue(sequence.requires_stop(params, {})) def test_requires_stop(self) -> None: pass - def test_runtime_mapping_exception(self): + def test_runtime_mapping_exception(self) -> None: mapping = copy.deepcopy(self.mapping1) mapping['up'] = "foo" @@ -140,6 +154,49 @@ def test_runtime_mapping_exception(self): with self.assertRaises(MissingParameterDeclarationException): SequencePulseTemplate(subtemplates, self.outer_parameters) + def test_crash(self) -> None: + table = TablePulseTemplate(identifier='foo') + table.add_entry('ta', 'va', interpolation='hold') + table.add_entry('tb', 'vb', interpolation='linear') + table.add_entry('tend', 0, interpolation='jump') + + 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' + } + sequence = SequencePulseTemplate([(table, first_mapping), (table, second_mapping)], external_parameters) + + parameters = { + 'ta': ConstantParameter(2), + 'va': ConstantParameter(2), + 'tb': ConstantParameter(4), + 'vb': ConstantParameter(3), + 'tc': ConstantParameter(5), + 'td': ConstantParameter(11), + 'tend': ConstantParameter(6)} + + sequencer = DummySequencer() + block = DummyInstructionBlock() + self.assertFalse(sequence.requires_stop(parameters, {})) + sequence.build_sequence(sequencer, parameters, {}, block) + from qctoolkit.pulses.plotting import Plotter + from qctoolkit.pulses.sequencing import Sequencer + s = Sequencer() + p = Plotter() + s.push(sequence, parameters) + s.build() + class SequencePulseTemplateStringTest(unittest.TestCase): def test_str(self): From e399848e4ea5a348ff82f9da2e16e6752ae0cac7 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Mon, 7 Dec 2015 17:43:45 +0100 Subject: [PATCH 11/33] Added two basic examples for pulse construction as Jupyter/IPython notebooks. --- examples/00SimpleTablePulse.ipynb | 257 ++++++++++++++++++++++++++++++ examples/01SequencePulse.ipynb | 174 ++++++++++++++++++++ examples/img/example_pulse.svg | 169 ++++++++++++++++++++ 3 files changed, 600 insertions(+) create mode 100644 examples/00SimpleTablePulse.ipynb create mode 100644 examples/01SequencePulse.ipynb create mode 100644 examples/img/example_pulse.svg diff --git a/examples/00SimpleTablePulse.ipynb b/examples/00SimpleTablePulse.ipynb new file mode 100644 index 000000000..7753d94ff --- /dev/null +++ b/examples/00SimpleTablePulse.ipynb @@ -0,0 +1,257 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modelling a Simple TablePulseTemplate\n", + "\n", + "This example demonstrates how to set up a simple TablePulseTemplate.\n", + "\n", + "\"The\n", + "\n", + "Assume we want to model a pulse as depicted by the figure above. Since the structure is relatively simple and relies only on a few critical points between which the values are interpolated (indicated by the crosses in the figure), we will do so by using a `TablePulseTemplate` and setting values at appropriate times. First, let us instantiate a `TablePulseTemplate` object:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import TablePulseTemplate\n", + "\n", + "template = TablePulseTemplate(identifier='foo')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For our first try, let's just fix some values for the parameters. Let us set $t_a$ = 2, $v_a$ = 2, $t_b$ = 4, $v_b$ = 3, $t_{end}$ = 6. Our pulse then holds a value of 0 for 2 units of time, then jumps to 2 and subsequently ramps to 3 over the next 2 units of time. Finally, it returns to holding 0 for another 2 units of time. The supporting points for the table are thus (0,0), (2,2), (4,3), (6,0). We add these to our `TablePulseTemplate` object `template` with the correct interpolation strategies as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "template.add_entry(0, 0)\n", + "template.add_entry(2, 2, interpolation='hold')\n", + "template.add_entry(4, 3, interpolation='linear')\n", + "template.add_entry(6, 0, interpolation='jump')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that we could omit the first instruction: If the time value of the first call to `add_entry` is greater than zero, a starting entry (0,0) is automatically set. Note further that the interpolation set for an entry always applies to the range from the previous entry to the new entry. Thus, the value for the first entry is always ignored. The default value for interpolation is 'hold'. 'hold' and 'jump' differ in that 'hold' will hold the previous value until the new entry is reached while 'jump' will immediately assume the value of the new entry.\n", + "\n", + "We plot `template` to see if everything is correct (ignore the matplotlib warning here):" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXcAAAEACAYAAABI5zaHAAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAALEgAACxIB0t1+/AAAFVpJREFUeJzt3X+Q3XV97/HnKwGKVBFRGxRi0QIz5dpKwIkUihysUog2\nWIZBmEEd2lGHEbVevdX6c+lMa++0UxEFzVjAiFZyRUipRhG5HIW2E0WSiBAUbqFNGAm0EaoElMj7\n/vE90nXdTXbz3d2z+93nY2Znv99z3ud83uPE1374nM/3e1JVSJK6ZdGwG5AkTT/DXZI6yHCXpA4y\n3CWpgwx3Seogw12SOqhVuCfZN8n6JBuT3JHkQ+PU9JI8nGTD4Od9bcaUJO3eXm1eXFWPJTmpqnYk\n2Qu4OcnvVtXNY0q/XlUr24wlSZq81ssyVbVjcLgPsBjYPk5Z2o4jSZq81uGeZFGSjcA24MaqumNM\nSQHHJdmUZF2SI9uOKUnatemYuT9RVUcBhwAvTdIbU3IrsLSqXgR8FFjbdkxJ0q5lOu8tk+T9wKNV\n9Te7qLkHOKaqto953JvcSNIUVdW4y95td8s8K8kBg+OnAK8ANoypWZIkg+PlNH9QxluXp6pm7OeD\nH/zgjL6/vdv/XP2x/+72viutdssAzwFWJ1lE84fiiqq6IcmbBmG9CjgDOC/JTmAHcFbLMSVJu9F2\nK+RtwNHjPL5q1PHFwMVtxpEkTc2CuUK11+sNu4U9Np97B/sfNvsfnmH2Pq0fqLaRpOZKL5I0HySh\nZuIDVUnS3GS4S1IHGe6S1EGGuyR1kOEuSR1kuEtSBxnuktRBhrskdZDhLkkdZLhLUgcZ7pLUQYa7\nJHWQ4S5JHWS4S1IHGe6S1EGGuyR1kOEuSR3UKtyT7JtkfZKNSe5I8qEJ6i5KcleSTUmWtRlTkrR7\nbb8g+7EkJ1XVjiR7ATcn+d2quvnnNUlWAIdV1eFJXgJ8HDi2XduSpF1pvSxTVTsGh/sAi4HtY0pW\nAqsHteuBA5IsaTuuJGlircM9yaIkG4FtwI1VdceYkoOBLaPOtwKHtB1XkjSxVssyAFX1BHBUkqcD\n1yXpVVV/TNnYb+eu8d5rZGTkyeNer0ev12vbnrQgPfIInHkmrFsH/T6ceOKwO9J06Pf79Pv9SdWm\natyc3SNJ3g88WlV/M+qxTwD9qrpycH4ncGJVbRvz2prOXqSFqAo+/GF4xzv++7EvfAFOP314PWnm\nJKGqxk6egfa7ZZ6V5IDB8VOAVwAbxpRdC7xuUHMs8NDYYJfU3je+AYsWNcH+5jfD44/DH/7hsLvS\nsLRdlnkOsDrJIpo/FFdU1Q1J3gRQVauqal2SFUnuBh4Bzm05pqRRHngAXvlKuOUWOPpo+OpX4ZnP\nHHZXGra2WyFvA44e5/FVY87PbzOOpF/2+OPwJ38Cl1zSnLu2rtG8QlWahz77WdhnnybY/+Iv4Ikn\nDHb9ota7ZSTNnrvuakL8Bz+AFStgzRp46lOH3ZXmImfu0jzw6KNw2mlwxBHNLP222+BLXzLYNTHD\nXZrDquAjH4H99oNrr22WY+6/H174wmF3prnOZRlpjrrpJjjpJPjZz+C88+Cii2Av/x+rSfKfijTH\nPPAAvOpV8K1vwW//Nnzta/DsZw+7K803LstIc8TOnfDWt8KSJU2w33ADbNpksGvPGO7SHLBmDey9\nN3z0o3DBBc2Hpi972bC70nzmsow0RPfeCyecAFu3wu//Pnz+8/C0pw27K3WBM3dpCB59FM44A57/\nfHjsMdi4Eb7yFYNd08dwl2ZRVbP0st9+zd0aP/MZePBBeNGLht2ZusZlGWmW/NM/NevoP/0pvOEN\ncPHFzTq7NBMMd2mGPfgg/MEfwPr1cOSRzS6Ygw4adlfqOpdlpBnys5/B298Ov/ZrTbBfdx3cfrvB\nrtlhuEsz4KqrmqtJL7wQ3v/+JuhPPnnYXWkhcVlGmkb/9m/w0pfCv/97E+ZXXeUOGA2HM3dpGjz6\nKJx1Fhx6aPPl1Bs2NMswBruGxXCXWqiCj32s2dq4Zg1ccQX8x3/AUUcNuzMtdC7LSHvoX/4Ffu/3\nmln7uefCqlVubdTc0WrmnmRpkhuT3J7ku0neOk5NL8nDSTYMft7XZkxp2P7zP+G445qf5z0PtmyB\nyy4z2DW3tJ25Pw68vao2Jnkq8O0k11fV5jF1X6+qlS3HkobqiSfg3e+Gv/7r5nzdOjj11OH2JE2k\n1cy9qu6vqo2D4x8Dm4HnjlOaNuNIw7Z2LSxe3AT7e97TbG002DWXTduae5JDgWXA+jFPFXBckk3A\nfcA7q+qO6RpXmklbtkCvB//6r/Dylzf3g9l//2F3Je3etIT7YEnmKuBtgxn8aLcCS6tqR5JTgbXA\nEeO9z8jIyJPHvV6PXq83He1JU/bYY/DHfwx///fw9Kc3WxvdAaNh6/f79Pv9SdWmqloNlmRv4IvA\nl6vqwknU3wMcU1XbxzxebXuR2qpqbuj1lrc055dd1uyEma9OPx3OOaf5re5JQlWNu+zdauaeJMCl\nwB0TBXuSJcADVVVJltP8Qdk+Xq00TN/8ZnPXxkcegde+Fi691B0wmr/aLsscD5wDfCfJhsFj7wGe\nB1BVq4AzgPOS7AR2AGe1HFOaVtu3w8qVzS15Dz8crr8efv3Xh92V1E6rcK+qm9nNjpuquhi4uM04\n0kyogve+Fz70oeb8i1+EV75yuD1J08XbD2hB+tKXYNGiJtjf/W7YudNgV7d4+wEtKFu3NrcM+P73\nm/X1tWu9uZe6yZm7FoSf/KT5kHTp0ibgb721+UYkg11dZbir06rgkktg332bL6P+xCea3TDLlg27\nM2lmuSyjzvr2t+Gkk+BHP4Kzz4ZPfQr22WfYXUmzw3BX5zz0EJx2GnzjG/AbvwEbN8ILXjDsrqTZ\n5bKMOqMKPvABeMYzmmD/h3+Au+822LUwOXNXJ3zlK/99l8Y//VP4y79s7uIoLVSGu+a1rVubL6Le\nvLm5e+Patc2NvqSFzmUZzUs/+Qm8/vXN1sZ77oFbboEbbzTYpZ8z3DWvVDXfVbrvvvDpTzdfTv3o\no3DMMcPuTJpbXJbRvLFpE5x4Ijz8MJx5ZhPuv/Irw+5KmpucuWvO+6//am4VcNRRzU6Yu+6CNWsM\ndmlXDHfNWVXw53/erKPfeGPzYek998Bhhw27M2nuc1lGc9L11ze7YADe+U74q79ya6M0FYa75pSt\nW+GUU+D22+H445t7rB9wwLC7kuYfl2U0J/z0p/BHf9Rsbfz+92H9erj5ZoNd2lOGu4aqCj75yebD\n0csvh7/922YP+/Llw+5Mmt9cltHQ3H47nHAC/PCHcMYZcMUVzf51Se21mrknWZrkxiS3J/lukrdO\nUHdRkruSbErinbQXuB/9qPmw9IUvhP33h+99Dz7/eYNdmk5tl2UeB95eVf8DOBZ4c5LfHF2QZAVw\nWFUdDrwR+HjLMTVPVTU39Np//2Y3zDXXwL33whFHDLszqXtahXtV3V9VGwfHPwY2A88dU7YSWD2o\nWQ8ckGRJm3E1/3zta80XUr/3vfCOdzRfSP3qVw+7K6m7pm3NPcmhwDJg/ZinDga2jDrfChwCbJuu\nsTV3PfRQ821IGzfCS14C69bBgQcOuyup+6Yl3JM8FbgKeNtgBv9LJWPOa7z3GRkZefK41+vR6/Wm\noz0N0XXXNcH+z/8Mv/M7w+5Gmt/6/T79fn9StakaN2cnLcnewBeBL1fVheM8/wmgX1VXDs7vBE6s\nqm1j6qptL5p71qyBq69ufmv2nX46nHNO81vdk4SqGjt5BtrvlglwKXDHeME+cC3wukH9scBDY4Nd\nkjS92i7LHA+cA3wnyYbBY+8BngdQVauqal2SFUnuBh4Bzm05piRpN1qFe1XdzCRm/1V1fptxJElT\n4+0HJKmDDHdJ6iDDXZI6yHCXpA4y3CWpgwx3Seogw12SOshwl6QOMtwlqYMMd0nqIMNdkjrIcJek\nDjLcJamDDHdJ6iDDXZI6yHCXpA4y3CWpgwx3Seogw12SOqh1uCe5LMm2JLdN8HwvycNJNgx+3td2\nTEnSrrX6guyBy4GPAp/eRc3Xq2rlNIwlSZqE1jP3qroJ+OFuytJ2HEnS5M3GmnsBxyXZlGRdkiNn\nYUxJWtCmY1lmd24FllbVjiSnAmuBI8YrHBkZefK41+vR6/VmoT1Jmh/6/T79fn9Stamq1gMmORT4\nx6r6rUnU3gMcU1Xbxzxe09GL5pY1a+Dqq5vfmn2nnw7nnNP8VvckoarGXfae8WWZJEuSZHC8nOYP\nyvbdvEyS1ELrZZkknwNOBJ6VZAvwQWBvgKpaBZwBnJdkJ7ADOKvtmJKkXWsd7lV19m6evxi4uO04\nkqTJ8wpVSeogw12SOshwl6QOMtwlqYMMd0nqIMNdkjrIcJekDjLcJamDDHdJ6iDDXZI6yHCXpA4y\n3CWpgwx3Seogw12SOshwl6QOMtwlqYMMd0nqIMNdkjrIcJekDmoV7kkuS7ItyW27qLkoyV1JNiVZ\n1mY8SdLktJ25Xw6cMtGTSVYAh1XV4cAbgY+3HE+SNAmtwr2qbgJ+uIuSlcDqQe164IAkS9qMKUna\nvZlecz8Y2DLqfCtwyAyPKUkL3l6zMEbGnNdEhSMjI08e93o9er3ezHQkSfNQv9+n3+9Pqnamw/0+\nYOmo80MGj41rdLhLkn7R2EnvBRdcMGHtTC/LXAu8DiDJscBDVbVthseUpAWv1cw9yeeAE4FnJdkC\nfBDYG6CqVlXVuiQrktwNPAKc27ZhSdLutQr3qjp7EjXntxlDkjR1XqEqSR1kuEtSBxnuktRBhrsk\ndZDhLkkdZLhLUgcZ7pLUQYa7JHWQ4S5JHWS4S1IHGe6S1EGGuyR1kOEuSR1kuEtSBxnuktRBhrsk\ndZDhLkkdZLhLUgcZ7pLUQa3DPckpSe5McleSd43zfC/Jw0k2DH7e13ZMSdKutfqC7CSLgY8BLwfu\nA76V5Nqq2jym9OtVtbLNWJKkyWs7c18O3F1V91bV48CVwGnj1KXlOJKkKWgb7gcDW0adbx08NloB\nxyXZlGRdkiNbjilJ2o1WyzI0wb07twJLq2pHklOBtcAR4xWOjIw8edzr9ej1ei3bk6Tu6Pf79Pv9\nSdW2Dff7gKWjzpfSzN6fVFU/GnX85SSXJDmwqraPfbPR4S5J+kVjJ70XXHDBhLVtl2VuAQ5PcmiS\nfYDXANeOLkiyJEkGx8uBjBfskqTp02rmXlU7k5wPXAcsBi6tqs1J3jR4fhVwBnBekp3ADuCslj1L\nknaj7bIMVfVl4MtjHls16vhi4OK240iSJs8rVCWpgwx3Seogw12SOshwl6QOMtwlqYMMd0nqIMNd\nkjrIcJekDjLcJamDDHdJ6iDDXZI6yHCXpA4y3CWpgwx3Seogw12SOshwl6QOMtwlqYMMd0nqIMNd\nkjqodbgnOSXJnUnuSvKuCWouGjy/KcmytmNKknatVbgnWQx8DDgFOBI4O8lvjqlZARxWVYcDbwQ+\n3mZMSdLutZ25Lwfurqp7q+px4ErgtDE1K4HVAFW1HjggyZKW40qSdmGvlq8/GNgy6nwr8JJJ1BwC\nbGs59qS99rWzNZLGuukmePGLh93FwvaRj8A11wy7i4Vp8WL41KeGM3bbcK9J1mUyrxsZGXnyuNfr\n0ev19qipsU4+eVreRnvg5JNhmZ+yDM3ICGzaNOwuFq5F07xlpd/v0+/3J1Wbqsnm8zgvTo4FRqrq\nlMH5nwFPVNX/HlXzCaBfVVcOzu8ETqyqbWPeq9r0IkkLTRKqauzkGWi/5n4LcHiSQ5PsA7wGuHZM\nzbXA6waNHAs8NDbYJUnTq9WyTFXtTHI+cB2wGLi0qjYnedPg+VVVtS7JiiR3A48A57buWpK0S62W\nZaaTyzKSNDUzuSwjSZqDDHdJ6iDDXZI6yHCXpA4y3CWpgwx3Seogw12SOshwl6QOMtwlqYMMd0nq\nIMNdkjrIcJekDjLcJamDDHdJ6iDDXZI6yHCXpA4y3CWpgwx3Seogw12SOmiPwz3JgUmuT/L9JF9N\ncsAEdfcm+U6SDUm+ueetttPv94c1dGvzuXew/2Gz/+EZZu9tZu7vBq6vqiOAGwbn4ymgV1XLqmp5\ni/Fa8R/I8Nj/cNn/8MzXcF8JrB4crwZevYvacb+dW5I0M9qE+5Kq2jY43gYsmaCugK8luSXJG1qM\nJ0mapFTVxE8m1wMHjfPUe4HVVfWMUbXbq+rAcd7jOVX1gyTPBq4H3lJVN41TN3EjkqRxVdW4KyN7\n7eZFr5jouSTbkhxUVfcneQ7wwATv8YPB7weTXAMsB34p3CdqUJI0dW2WZa4FXj84fj2wdmxBkv2S\nPG1w/KvAycBtLcaUJE3CLpdldvnC5EDg/wDPA+4Fzqyqh5I8F/hkVb0yyQuAqwcv2Qv4bFV9qH3b\nkqRd2eNwlyTNXZ2/QjXJKUnuTHJXkncNu5+pSHLZ4LONebmUlWRpkhuT3J7ku0neOuyepiLJvknW\nJ9mY5I4k8+6/OpMsHlxA+I/D7mWq5soFkHsqyQFJrkqyefDv59hZHb/LM/cki4HvAS8H7gO+BZxd\nVZuH2tgkJTkB+DHw6ar6rWH3M1VJDgIOqqqNSZ4KfBt49Xz53x+az42qakeSvYCbgXdW1c3D7muy\nkvxP4BjgaVW1ctj9TEWSe4Bjqmr7sHvZE0lWA1+vqssG/35+taoenq3xuz5zXw7cXVX3VtXjwJXA\naUPuadIGW0Z/OOw+9lRV3V9VGwfHPwY2A88dbldTU1U7Bof7AIuBeRM0SQ4BVgB/x/y9kHBe9p3k\n6cAJVXUZQFXtnM1gh+6H+8HAllHnWwePaZYlORRYBqwfbidTk2RRko00F+rdWFV3DLunKfgw8L+A\nJ4bdyB6azxdAPh94MMnlSW5N8skk+81mA10P9+6uOc0jgyWZq4C3DWbw80ZVPVFVRwGHAC9N0hty\nS5OS5FXAA1W1gXk6+wWOr6plwKnAmwfLlPPFXsDRwCVVdTTwCBPff2tGdD3c7wOWjjpfSjN71yxJ\nsjfwBeAzVfVL10LMF4P/pP4S8OJh9zJJxwErB+vWnwNeluTTQ+5pSkZfAAn8/ALI+WIrsLWqvjU4\nv4om7GdN18P9FuDwJIcm2Qd4Dc3FV5oFSQJcCtxRVRcOu5+pSvKsn9/KOslTgFcAG4bb1eRU1Xuq\namlVPR84C/i/VfW6Yfc1WfP9Asiquh/YkuSIwUMvB26fzR52efuB+a6qdiY5H7iO5sOwS+fZTo3P\nAScCz0yyBfhAVV0+5Lam4njgHOA7SX4ein9WVV8ZYk9T8RxgdZJFNBOhK6rqhiH3tKfm2xLlEuCa\nZn7w5AWQXx1uS1P2FuCzg4nl/wPOnc3BO70VUpIWqq4vy0jSgmS4S1IHGe6S1EGGuyR1kOEuSR1k\nuEtSBxnuktRB/x9Z0wZxl95wXAAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "from qctoolkit.pulses import plot\n", + "\n", + "plot(template, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Alright, we got what we wanted. \n", + "\n", + "## Introducing Parameters\n", + "Now we want to make the template parameterizable. This allows us to reuse the template for pulses with similar structure. Say we would like to have the same pulse, but the intermediate linear interpolation part should last 4 units of time instead of only 2. Instead of creating another template with hardcoded values, we instruct the `TablePulseTemplate` instance to rely on parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "param_template = TablePulseTemplate()\n", + "param_template.add_entry('ta', 'va', interpolation='hold')\n", + "param_template.add_entry('tb', 'vb', interpolation='linear')\n", + "param_template.add_entry('tend', 0, interpolation='jump')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Instead of using numerical values, we simply insert parameter names in our calls to `add_entry`. You can use any combination of numerical values or parameters names here. Note that we also gave our object the optional identifier 'foo'. Our `param_template` thus now defines a set of parameters." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "{'tb', 'vb', 'ta', 'va', 'tend'}\n" + ] + } + ], + "source": [ + "print(param_template.parameter_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now have a pulse template that we can instantiate with different parameter values, which we simply provide as a dictionary. To achieve the same pulse as above:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "parameters = {'ta': 2,\n", + " 'va': 2,\n", + " 'tb': 4,\n", + " 'vb': 3,\n", + " 'tend': 6}\n", + "plot(param_template, parameters, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "To instantiate the pulse with longer intermediate linear interpolation we now simply adjust the parameter values without touching the `param_template` itself:" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\nQSHWiZW2AAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "parameters = {'ta': 2,\n", + " 'va': 2,\n", + " 'tb': 6,\n", + " 'vb': 3,\n", + " 'tend': 8}\n", + "plot(param_template, parameters, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Yay!" + ] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/01SequencePulse.ipynb b/examples/01SequencePulse.ipynb new file mode 100644 index 000000000..a3769b4a1 --- /dev/null +++ b/examples/01SequencePulse.ipynb @@ -0,0 +1,174 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Combining PulseTemplates Using SequencePulseTemplate\n", + "\n", + "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](00SimpleTablePulse.ipynb). We will also map the parameters such that we can individually adapt values in either of the two subtemplates.\n", + "\n", + "We start with the defintion of the `TablePulseTemplate`:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import TablePulseTemplate\n", + "\n", + "template = TablePulseTemplate(identifier='foo')\n", + "template.add_entry('ta', 'va', interpolation='hold')\n", + "template.add_entry('tb', 'vb', interpolation='linear')\n", + "template.add_entry('tend', 0, interpolation='jump')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Constructing a sequence of two of these requires us to set up a `SequencePulseTemplate` instance which expects a list of subtemplates, a set of external parameters and corresponding parameters mappings:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import SequencePulseTemplate\n", + "\n", + "external_parameters = ['ta', 'tb', 'tc', 'td', 'va', 'vb', 'tend']\n", + "first_mapping = {\n", + " 'ta': 'ta',\n", + " 'tb': 'tb',\n", + " 'va': 'va',\n", + " 'vb': 'vb',\n", + " 'tend': 'tend'\n", + "}\n", + "second_mapping = {\n", + " 'ta': 'tc',\n", + " 'tb': 'td',\n", + " 'va': 'vb',\n", + " 'vb': 'va + vb',\n", + " 'tend': '2 * tend'\n", + "}\n", + "sequence = SequencePulseTemplate([(template, first_mapping),\n", + " (template, second_mapping)],\n", + " external_parameters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our sequence now exposes the parameters declared in the `external_parameters` set:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "frozenset({'td', 'tc', 'ta', 'vb', 'va', 'tb', 'tend'})\n" + ] + } + ], + "source": [ + "print(sequence.parameter_names)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "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.\n", + "\n", + "Let's throw in some values and plot our sequence:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "from qctoolkit.pulses import plot\n", + "\n", + "parameters = {'ta': 2,\n", + " 'va': 2,\n", + " 'tb': 4,\n", + " 'vb': 3,\n", + " 'tc': 5,\n", + " 'td': 11,\n", + " 'tend': 6}\n", + "plot(sequence, parameters, sample_rate=100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/img/example_pulse.svg b/examples/img/example_pulse.svg new file mode 100644 index 000000000..58591ab16 --- /dev/null +++ b/examples/img/example_pulse.svg @@ -0,0 +1,169 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + V + b + V + a + 0 + 0 + t + b + t + a + t + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear interpolation + + + + + + + + + + Hold interpolation + + + + + + + + + + “Inverse hold” interpolation + + + + + Supporting point + Pulse voltage + + + + + + + + + + + + + + + + + + +length + + + + + + + + + +start + From 6dbf45465c5aa87d09b320790e0126aced831445 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Thu, 17 Dec 2015 10:13:51 +0100 Subject: [PATCH 12/33] Fixed MATLAB/qctoolkitExample.m --- MATLAB/qctoolkitExample.m | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MATLAB/qctoolkitExample.m b/MATLAB/qctoolkitExample.m index 8fd444da4..84071b001 100644 --- a/MATLAB/qctoolkitExample.m +++ b/MATLAB/qctoolkitExample.m @@ -35,8 +35,7 @@ sequencer.push(table_pulse_1, parameters); sequencer.push(table_pulse_1, parameters); -block = sequencer.build(); -sequence = block.compile_sequence(); +sequence = sequencer.build(); % Convert the instruction sequence to pulse_control pulses and a % pulse_group From 6f72aa98ba26db5e95353ccac5ef0684f72c15d8 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Sun, 27 Dec 2015 13:11:57 +0100 Subject: [PATCH 13/33] Removed alternative usage of numexpr instead of py_expression_eval in class Expression. Caused weird behavior. --- qctoolkit/expressions.py | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/qctoolkit/expressions.py b/qctoolkit/expressions.py index 8162765a6..fe18ef7f3 100644 --- a/qctoolkit/expressions.py +++ b/qctoolkit/expressions.py @@ -1,8 +1,3 @@ -try: - import numexpr - USE_NUMEXPR = True -except ImportError: - USE_NUMEXPR = False from py_expression_eval import Parser from typing import Any, Dict, Iterable, Optional @@ -25,10 +20,7 @@ def variables(self) -> Iterable[str]: return self.__expression.variables() def evaluate(self, **kwargs) -> float: - if USE_NUMEXPR: - return numexpr.evaluate(self.__string, global_dict={}, local_dict=kwargs) - else: - return self.__expression.evaluate(kwargs) + return self.__expression.evaluate(kwargs) def get_serialization_data(self, serializer: 'Serializer') -> Dict[str, Any]: return dict(type='Expression', expression=self.__string) From b4e3043884d332f6c169fa4549fa8cca4b59da43 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Sun, 27 Dec 2015 13:12:19 +0100 Subject: [PATCH 14/33] Serializer now overwrites existing files. --- qctoolkit/serialization.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qctoolkit/serialization.py b/qctoolkit/serialization.py index a0d4d05f7..5e2556558 100644 --- a/qctoolkit/serialization.py +++ b/qctoolkit/serialization.py @@ -128,7 +128,7 @@ def serialize(self, serializable: Serializable) -> None: storage_identifier = identifier if identifier == '': storage_identifier = 'main' - self.__storage_backend.put(storage_identifier, json.dumps(repr_[identifier], indent=4, sort_keys=True)) + self.__storage_backend.put(storage_identifier, json.dumps(repr_[identifier], indent=4, sort_keys=True), True) def deserialize(self, representation: Union[str, Dict[str, Any]]) -> Serializable: if isinstance(representation, str): From 55a09b4c38ee1440f0f286927fab6b519a0aa807 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Sun, 27 Dec 2015 13:14:37 +0100 Subject: [PATCH 15/33] Changes to FunctionPulseTemplate: Added identifier member. Evaluated parameter values are passed to expressions and FunctionWaveform instead of Parameter objects. (Expressions and Waveforms shouldn't know about Parameter class). --- qctoolkit/pulses/function_pulse_template.py | 12 ++++++------ tests/pulses/function_pulse_tests.py | 5 +++-- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/qctoolkit/pulses/function_pulse_template.py b/qctoolkit/pulses/function_pulse_template.py index e3de7b82b..67896e242 100644 --- a/qctoolkit/pulses/function_pulse_template.py +++ b/qctoolkit/pulses/function_pulse_template.py @@ -33,8 +33,8 @@ class FunctionPulseTemplate(PulseTemplate): The independent variable in the expression is called 't' and is given in units of nano-seconds. """ - def __init__(self, expression: str, duration_expression: str, measurement: bool=False) -> None: - super().__init__() + def __init__(self, expression: str, duration_expression: str, measurement: bool=False, identifier: str=None) -> None: + super().__init__(identifier) self.__expression = Expression(expression) self.__duration_expression = Expression(duration_expression) self.__is_measurement_pulse = measurement # type: bool @@ -50,12 +50,12 @@ def parameter_declarations(self) -> Set[ParameterDeclaration]: """Return a set of all parameter declaration objects of this TablePulseTemplate.""" return set() - def get_pulse_length(self, parameters) -> float: + def get_pulse_length(self, parameters: Dict[str, Parameter]) -> float: """Return the length of this pulse for the given parameters.""" missing = self.__parameter_names - set(parameters.keys()) for m in missing: raise ParameterNotProvidedException(m) - return self.__duration_expression.evaluate(**parameters) + return self.__duration_expression.evaluate(**{parameter_name: parameter.get_value() for (parameter_name, parameter) in parameters.items()}) def get_measurement_windows(self, parameters: Optional[Dict[str, Parameter]] = {}) -> List[MeasurementWindow]: """Return all measurement windows defined in this PulseTemplate. @@ -78,7 +78,7 @@ def build_sequence(self, parameters: Dict[str, Parameter], conditions: Dict[str, 'Condition'], instruction_block: InstructionBlock) -> None: - waveform = FunctionWaveform(parameters, self.__expression, self.__duration_expression) + waveform = FunctionWaveform({parameter_name: parameter.get_value() for (parameter_name, parameter) in parameters.items()}, self.__expression, self.__duration_expression) instruction_block.add_instruction_exec(waveform) def requires_stop(self, parameters: Dict[str, Parameter], conditions: Dict[str, 'Condition']) -> bool: @@ -100,7 +100,7 @@ def deserialize(serializer: 'Serializer', **kwargs) -> 'Serializable': class FunctionWaveform(Waveform): - def __init__(self, parameters: Dict[str, Parameter], expression: Expression, duration_expression: Expression) -> None: + def __init__(self, parameters: Dict[str, float], expression: Expression, duration_expression: Expression) -> None: super().__init__() self.__expression = expression self.__parameters = parameters diff --git a/tests/pulses/function_pulse_tests.py b/tests/pulses/function_pulse_tests.py index 7a2d5440c..38c04dcd0 100644 --- a/tests/pulses/function_pulse_tests.py +++ b/tests/pulses/function_pulse_tests.py @@ -4,6 +4,7 @@ FunctionWaveform from qctoolkit.pulses.sequencing import Sequencer from qctoolkit.pulses.instructions import InstructionBlock +from qctoolkit.pulses.parameters import ConstantParameter from tests.serialization_dummies import DummySerializer from qctoolkit.expressions import Expression @@ -14,7 +15,7 @@ class FunctionPulseTest(unittest.TestCase): def setUp(self): self.s = 'a + b' self.s2 = 'c' - self.pars = dict(a=1, b=2, c=3) + self.pars = dict(a=ConstantParameter(1), b=ConstantParameter(2), c=ConstantParameter(3)) self.fpt = FunctionPulseTemplate(self.s, self.s2) def test_get_pulse_length(self): @@ -39,7 +40,7 @@ def setUp(self): unittest.TestCase.setUp(self) self.f = "a * t" self.duration = "y" - self.args = dict(a=3,y=1) + self.args = dict(a=ConstantParameter(3),y=ConstantParameter(1)) self.fpt = FunctionPulseTemplate(self.f, self.duration) def test_build_sequence(self): From b053f9b380b2b8b3d22021cc660105b6a67361ec Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Sun, 27 Dec 2015 14:47:06 +0100 Subject: [PATCH 16/33] Some examples as iPython Notebooks. Not done yet. --- examples/00SimpleTablePulse.ipynb | 31 ++- examples/02FunctionPulse.ipynb | 127 +++++++++++ examples/03Serialization.ipynb | 204 +++++++++++++++++ examples/04Sequencing.ipynb | 155 +++++++++++++ examples/05Parameters.ipynb | 210 ++++++++++++++++++ examples/06Branching.ipynb | 32 +++ examples/serialized_pulses/main | 65 ++++++ examples/serialized_pulses/sequence_embedded | 81 +++++++ .../serialized_pulses/sequence_referenced | 17 ++ examples/serialized_pulses/stored_template | 34 +++ examples/serialized_pulses/table_template | 65 ++++++ 11 files changed, 1010 insertions(+), 11 deletions(-) create mode 100644 examples/02FunctionPulse.ipynb create mode 100644 examples/03Serialization.ipynb create mode 100644 examples/04Sequencing.ipynb create mode 100644 examples/05Parameters.ipynb create mode 100644 examples/06Branching.ipynb create mode 100644 examples/serialized_pulses/main create mode 100644 examples/serialized_pulses/sequence_embedded create mode 100644 examples/serialized_pulses/sequence_referenced create mode 100644 examples/serialized_pulses/stored_template create mode 100644 examples/serialized_pulses/table_template diff --git a/examples/00SimpleTablePulse.ipynb b/examples/00SimpleTablePulse.ipynb index 7753d94ff..9caf3a6a2 100644 --- a/examples/00SimpleTablePulse.ipynb +++ b/examples/00SimpleTablePulse.ipynb @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 3, "metadata": { "collapsed": false }, @@ -58,7 +58,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 4, "metadata": { "collapsed": false }, @@ -75,7 +75,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -101,7 +101,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 5, "metadata": { "collapsed": true }, @@ -122,7 +122,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 6, "metadata": { "collapsed": false }, @@ -131,7 +131,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'tb', 'vb', 'ta', 'va', 'tend'}\n" + "{'tb', 'tend', 'vb', 'ta', 'va'}\n" ] } ], @@ -148,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -165,7 +165,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -191,7 +191,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 8, "metadata": { "collapsed": false }, @@ -208,7 +208,7 @@ "data": { "image/png": "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\nQSHWiZW2AAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -231,6 +231,15 @@ "source": [ "Yay!" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/examples/02FunctionPulse.ipynb b/examples/02FunctionPulse.ipynb new file mode 100644 index 000000000..5bb99a684 --- /dev/null +++ b/examples/02FunctionPulse.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Modelling Pulses Using Functions And Expressions\n", + "\n", + "Assume we want to model a pulse that represents a damped sine function. While we could, in theory, do this using `TablePulseTemplate`s by piecewise linear approximation (cf. [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb)), this would be a tedious endeavor. A much simpler approach presents itself in the form of the `FunctionPulseTemplate` class of the qctoolkit. Like the `TablePulseTemplate`, a `FunctionPulseTemplate` represents an atomic pulse which will be converted into a waveform for execution. The difference between both is that `FunctionPulseTemplate` accepts a mathematical expression which is parsed and evaluated using `py_expression_eval` to sample the waveform instead of the linear interpolation between specified supporting points as it is done in `TablePulseTemplate`.\n", + "\n", + "To define the sine function pulse template, we can thus do the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from qctoolkit.pulses import FunctionPulseTemplate\n", + "\n", + "template = FunctionPulseTemplate('exp(-t/2)*sin(2*t)', '2*3.1415')\n", + "\n", + "%matplotlib inline\n", + "from qctoolkit.pulses import plot\n", + "\n", + "plot(template, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first argument to `FunctionPulseTemplate`'s constructor is the string representation of the formula that the pulse represents. The second argument is used to compute the length of the pulse. In this case, this is simply a constant expression. Refer to [py-expression-eval's documentation](https://github.com/AxiaCore/py-expression-eval#available-operators-constants-and-functions) to read about the usable operators and functions in the expressions.\n", + "\n", + "The `t` is reserved as the free variable of the time domain in the first argument and must be present. Other variables can be used at will and corresponding values have to be passed in as a parameter when instantiating the `FunctionPulseTemplate`:" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false, + "scrolled": true + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "param_template = FunctionPulseTemplate('exp(-t/lambda)*sin(phi*t)', 'duration')\n", + "\n", + "%matplotlib inline\n", + "from qctoolkit.pulses import plot\n", + "\n", + "plot(param_template, {'lambda': 4, 'phi': 8, 'duration': 4*3.1415}, sample_rate=100)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/03Serialization.ipynb b/examples/03Serialization.ipynb new file mode 100644 index 000000000..6514f5495 --- /dev/null +++ b/examples/03Serialization.ipynb @@ -0,0 +1,204 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Storing Pulse Templates: Serialization\n", + "\n", + "So far, we have constructed new pulse templates in code for each session (which were discarded afterwards). We now want to store them persistently in the file system to be able to reuse them in later sessions. For this, qctoolkit offers us serialization and deserialization using the `Serializer` and `StorageBackend` classes.\n", + "\n", + "## Serializing Atomic Templates\n", + "### Storing" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import TablePulseTemplate\n", + "from qctoolkit.serialization import Serializer, FilesystemBackend\n", + "\n", + "anonymous_table = TablePulseTemplate()\n", + "anonymous_table.add_entry('ta', 'va', interpolation='hold')\n", + "anonymous_table.add_entry('tb', 'vb', interpolation='linear')\n", + "anonymous_table.add_entry('tend', 0, interpolation='jump')\n", + "\n", + "backend = FilesystemBackend(\"./serialized_pulses\")\n", + "serializer = Serializer(backend)\n", + "\n", + "serializer.serialize(anonymous_table)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Assuming that we, again, have the `TablePulseTemplate` from [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb) we instantiate a `Serializer` object to store it. `Serializer` requires a `StorageBackend` instance which represents the actual data storage. We provide a `FilesystemBackend` instance which will store data in the directory `./serialized_pulses`. With this setup, storing the pulse template simply means invoking the `serialize` method of the `Serializer` instance and passing in our template. This will store a JSON representation of the object in the specified storage. Since we have not provided any file name, `Serializer` chooses the file name as [`main`](serialized_pulses/main).\n", + "\n", + "To specify a name, we can provide an identifier as an argument to the constructor of any pulse template:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "identified_table = TablePulseTemplate(identifier='table_template')\n", + "identified_table.add_entry('ta', 'va', interpolation='hold')\n", + "identified_table.add_entry('tb', 'vb', interpolation='linear')\n", + "identified_table.add_entry('tend', 0, interpolation='jump')\n", + "\n", + "serializer.serialize(identified_table)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This will create a file named [`table_template`](serialized_pulses/table_template) with the same contents as above.\n", + "\n", + "### Loading\n", + "\n", + "To load a previously stored pulse template, we use the method `Serializer.deserialize` with the file name. The following code will load a very simple table pulse template which ramps from 0 to 20 over a duration of 4 units of time and which is stored under the name [`stored_template`](serialized_pulses/stored_template):" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\nAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "loaded_template = serializer.deserialize('stored_template')\n", + "\n", + "%matplotlib inline\n", + "from qctoolkit.pulses import plot\n", + "\n", + "plot(loaded_template, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Serializing Composite Templates\n", + "\n", + "Serializing atomic templates (`TablePulseTemplate` and `FunctionPulseTemplate`) is a straightforward task. However, when storing composite templates that refer to subtemplates, e.g., `SequencePulseTemplate`, one must decide whether to embed the subtemplates into the composite's serialization or to store them separately. The latter one will be preferred if the subtemplate is used in several composite templates. `Sequencer` will decide whether to store a subtemplate separately based on the fact whether or not it provides an identifier: Subtemplates without an identifier will be embedded." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import SequencePulseTemplate\n", + "\n", + "mapping = {\n", + " 'ta': '1',\n", + " 'tb': '2',\n", + " 'va': '5',\n", + " 'vb': '0',\n", + " 'tend': '5'\n", + "}\n", + "sequence1 = SequencePulseTemplate([(anonymous_table, mapping)], {}, identifier='sequence_embedded')\n", + "serializer.serialize(sequence1)\n", + "\n", + "sequence2 = SequencePulseTemplate([(identified_table, mapping)], {}, identifier='sequence_referenced')\n", + "serializer.serialize(sequence2)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The above code snippet creates two `SequencePulseTemplate`s consisting of only one table subtemplate (one of those defined above respectively). The `anonymous_table` is used in `sequence1`. Since it has no identifier, it is embedded in the serialization: [`sequence_embedded`](serialized_pulses/sequence_embedded).\n", + "\n", + "In contrast, the table subtemplate in `sequence2` has an identifier, so the serialization of `sequence2` will contain only a reference to the serialization of `identified_table`: [`sequence_referenced`](serialized_pulses/sequence_referenced). " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Storage Backends\n", + "\n", + "So far, we have only used the `FilesystemBackend` to store pulse template directly in some folder. However, the abstraction of the `StorageBackend` theoretically allows us to implement other backends, e.g., a SQL database, without changing the `Serializer`.\n", + "\n", + "Additionally, the class `CachingBackend` can be used to decorate and add caching functionality to any other `StorageBackend` instance to speed up loading of frequently accessed templates as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from qctoolkit.serialization import CachingBackend\n", + "cached_serializer = Serializer(CachingBackend(FilesystemBackend(\"./serialized_pulses\")))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/04Sequencing.ipynb b/examples/04Sequencing.ipynb new file mode 100644 index 000000000..4d63a4b39 --- /dev/null +++ b/examples/04Sequencing.ipynb @@ -0,0 +1,155 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Sequencing Process: Obtaining Pulse Instances From Pulse Templates\n", + "\n", + "In the previous examples, we have modelled pulses using the basic members of qctoolkit's `PulseTemplate` class hierarchy. However, these are only templates (or classes) of pulses and may contain parameters so that they cannot be run directly on hardware. First, we have to instantiate concrete waveforms and instructions in which order these will be run. This process is called _sequencing_ in the qctoolkit. It involves the instantiations of parameters with concrete values and the sampling of atomic pulse templates (`TablePulseTemplate` and `FunctionPulseTemplate`) to obtain waveforms. _Sequencing_ is performed by the `Sequencer` class. This example will explore how.\n", + "\n", + "First, let's assume we have the `PulseTemplate`s from the examples [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb) and [Modelling Pulses Using Functions And Expressions](02FunctionPulse.ipynb) composed in a `SequencePulseTable` (cf. [Combining PulseTemplates Using SequencePulseTemplate](01SequencePulse.ipynb)) with some parameter mappings:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\nwlKnmzeDeQAAAABJRU5ErkJggg==\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "from qctoolkit.pulses import TablePulseTemplate, FunctionPulseTemplate, SequencePulseTemplate, plot\n", + "\n", + "table_template = TablePulseTemplate()\n", + "table_template.add_entry('ta', 'va', interpolation='hold')\n", + "table_template.add_entry('tb', 'vb', interpolation='linear')\n", + "table_template.add_entry('tend', 0, interpolation='jump')\n", + "\n", + "function_template = FunctionPulseTemplate('exp(-t/lambda)*sin(phi*t)', 'duration')\n", + "\n", + "table_parameter_mapping = {\n", + " 'ta': 'ta',\n", + " 'tb': 'ta + duration',\n", + " 'tend': '15',\n", + " 'va': 'va',\n", + " 'vb': '0'\n", + "}\n", + "function_parameter_mapping = {\n", + " 'lambda': 'lambda',\n", + " 'phi': 'phi',\n", + " 'duration': 'duration'\n", + "}\n", + "sequence_template = SequencePulseTemplate([(table_template, table_parameter_mapping),\n", + " (function_template, function_parameter_mapping)],\n", + " {'ta', 'duration', 'va', 'lambda', 'phi'})\n", + "\n", + "\n", + "plot(sequence_template, {'lambda': 4, 'phi': 8, 'duration': 4*3.1415, 'ta': 1, 'va': 2}, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While the plot illustrates how the pulse will look like for the given parameter values, the object structure we created is only an abstract representation of pulses with this structure. (This is the reason we always have to provide specific parameters values for plotting.)\n", + "To convert this tree-like object structure into something the hardware understands, we will use the `Sequencer` class:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, , ]\n" + ] + } + ], + "source": [ + "from qctoolkit.pulses import Sequencer\n", + "\n", + "sequencer = Sequencer()\n", + "\n", + "sequencer.push(sequence_template, {'lambda': 4, 'phi': 8, 'duration': 4*3.1415, 'ta': 1, 'va': 2})\n", + "instruction_sequence = sequencer.build()\n", + "print(instruction_sequence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Using the `push` method of `Sequencer`, we add `PulseTemplate` objects to the sequencing stack, i.e., the last pushed object will be sequenced first. We then invoke the `build` method to start the sequencing process, which will process all objects on the stack and return a sequence of hardware instructions. As you can see in the output of the above code snippet, the `Sequencer` created a sequence of two `EXECInstruction`s and a `STOPInstruction`. The two `EXECInstruction`s refer to waveforms obtained by sampling the atomic template objects `table_template` and `function_template` of which the `sequence_template` we've sequenced is composed.\n", + "\n", + "The instruction sequence will afterwards be passed to a hardware-dependent interpreter which will configure the corresponding device accordingly. Note that the `plot` function internally employs sequencing and then simply plots the generated waveforms.\n", + "\n", + "## Side Note: Instructions\n", + "\n", + "The generated instruction sequence will consist of some of the following instructions:\n", + "- EXECInstruction: execute a waveform\n", + "- STOPInstruction: stop the execution\n", + "- JUMPInstruction: jump to some instruction in the instruction sequence based on some trigger/condition\n", + "- GOTOInstruction: go to some instruction in the instruction sequence\n", + "\n", + "The latter two will only be generated when hardware-based conditional branching is used in `LoopPulseTemplate` and `BranchPulseTemplate`. This was the main motivator for the usage of such an instruction sequence rather than just compling one large waveform.\n", + "Using only the `PulseTemplate`s discussed so far, only `EXECInstruction`s and a final `STOPInstruction` will be output by the `Sequencer`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/05Parameters.ipynb b/examples/05Parameters.ipynb new file mode 100644 index 000000000..a8c21a16f --- /dev/null +++ b/examples/05Parameters.ipynb @@ -0,0 +1,210 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# More Sophisticated Parameters\n", + "\n", + "So far we have only considered constant parameter values. Now assume that we need to derive the value for a parameter based on some measurements we've made during the execution of previous parts of a composite pulse. For example, let the pulse we want to execute be constructed as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "%matplotlib inline\n", + "from qctoolkit.pulses import TablePulseTemplate, SequencePulseTemplate, plot\n", + "\n", + "init_template = TablePulseTemplate()\n", + "init_template.add_entry(2, 5)\n", + "init_template.add_entry(4, -5)\n", + "init_template.add_entry(6, 0)\n", + "init_template.add_entry(8, 0)\n", + "\n", + "measurement_template = TablePulseTemplate(measurement=True)\n", + "measurement_template.add_entry(0, 2)\n", + "measurement_template.add_entry(4, 0)\n", + "\n", + "dependent_template = TablePulseTemplate()\n", + "dependent_template.add_entry(2, 0)\n", + "dependent_template.add_entry(5, 'v', 'linear')\n", + "dependent_template.add_entry(10, 0, 'linear')\n", + "\n", + "sequence_template = SequencePulseTemplate([(init_template, {}),\n", + " (measurement_template, {}),\n", + " (dependent_template, {'v': 'v'}),\n", + " (init_template, {})\n", + " ], {'v'})\n", + "\n", + "plot(sequence_template, {'v': 1}, sample_rate=100)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we want to let the value of parameter `v` depend somehow on the measurement we make between time 8 and 12 (assuming we have a way to obtain measurement data, which is currently not the case (work in progress)). Thus we need to execute the first part of the pulse, then compute the parameter value and execute the remainder. We can do so be encapsulating the computation of the parameter value in a custom subclass of `Parameter`. Assuming, for simplicity, that we have some `measurement_manager` object which we can query whether or not the measurement has been made (`is_measurement_available()`) and what data was obtained (`get_data()`) and that the value of `v` shall simply be twice the measured data, this subclass might look like this:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import Parameter\n", + "\n", + "class MeasurementDependentParameter:\n", + " \n", + " def __init__(self, measurement_manager) -> None:\n", + " self.measurement_manager = measurement_manager\n", + " \n", + " @property\n", + " def requires_stop(self) -> bool:\n", + " return not self.measurement_manager.is_measurement_available()\n", + " \n", + " def get_value(self) -> float:\n", + " return 2*(self.measurement_manager.get_data())" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We overwrite the abstract property `requires_stop` and the abstract method `get_value` of the `Parameter` base class. `requires_stop` is used to indicate to the `Sequencer` whether the `Parameter` object can currently be evaluated or whether the sequencing process has to be interrupted. Our `MeasurementDependentParameter` will return `True` if no measurement data is available (in contrast, the `ConstantParameter` - which internally represents any float value passed in - always returns `False`). The `get_value` method returns the parameter value. It is only called if `requires_stop` is false. In the `MesaurementDependentParameter` class, we assume that the measured data is a single float and that we simple want to multiply it by 2 as the parameter's value.\n", + "\n", + "We would then set up our pulse for execution like as in the following snippet (including a stub implementation of a `MeasurementManager` just for demonstration purposes):" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import Sequencer\n", + "\n", + "# We define a stub for the measurement manager here only for illustration purposes.\n", + "# It will state that a measurement is available iff Sequencer has interrupted its operation\n", + "class MeasurementManager:\n", + " def __init__(self, sequencer: Sequencer) -> None:\n", + " self.sequencer = sequencer\n", + " self.call_count = 0\n", + " \n", + " def is_measurement_available(self) -> bool:\n", + " is_available = self.call_count > 0\n", + " self.call_count += 1\n", + " return is_available\n", + " \n", + " def get_data(self) -> float:\n", + " return 3\n", + "\n", + "sequencer = Sequencer()\n", + "measurement_manager = MeasurementManager(sequencer)\n", + "parameter = MeasurementDependentParameter(measurement_manager)\n", + "\n", + "sequencer.push(init_template)\n", + "sequencer.push(dependent_template, {'v': parameter})\n", + "sequencer.push(measurement_template)\n", + "sequencer.push(init_template)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `MeasurementManager.is_measurement_available` stub will simply return `False` in the first invocation of `Sequencer.build` and `True` iff the `Sequencer` was interrupted before, simulating that some data is measured during the execution of the first part of the pulse.\n", + "\n", + "When we invoke `Sequencer.build`, for each template on the sequencing stack it first queries whether or not all parameters can be evaluated. If any of them returns `True` via the `requires_stop` method, the sequencing process will be interrupted.\n", + "In our example, `Sequencer` will first proceed through the first two subtemplates of `sequence_template`. When it arrives at `dependent_template`, it will stop:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "ename": "TypeError", + "evalue": "float() argument must be a string or a number, not 'MeasurementDependentParameter'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfirst_sequence\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msequencer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuild\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfirst_sequence\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\sequencing.py\u001b[0m in \u001b[0;36mbuild\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 101\u001b[0m \u001b[0mshall_continue\u001b[0m \u001b[1;33m|=\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 102\u001b[0m \u001b[0msequencing_stack\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 103\u001b[1;33m \u001b[0melement\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuild_sequence\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mconditions\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtarget_block\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 104\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;32mbreak\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\table_pulse_template.py\u001b[0m in \u001b[0;36mbuild_sequence\u001b[1;34m(self, sequencer, parameters, conditions, instruction_block)\u001b[0m\n\u001b[0;32m 314\u001b[0m \u001b[0mconditions\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mCondition\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 315\u001b[0m instruction_block: InstructionBlock) -> None:\n\u001b[1;32m--> 316\u001b[1;33m \u001b[0minstantiated\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_entries_instantiated\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 317\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0minstantiated\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 318\u001b[0m \u001b[0mwaveform\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mTableWaveform\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minstantiated\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\table_pulse_template.py\u001b[0m in \u001b[0;36mget_entries_instantiated\u001b[1;34m(self, parameters)\u001b[0m\n\u001b[0;32m 277\u001b[0m \u001b[1;31m# resolve voltage parameter references only if voltageParameters argument is not None, otherwise they are irrelevant\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 278\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mentry\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParameterDeclaration\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 279\u001b[1;33m \u001b[0mvoltage_value\u001b[0m\u001b[1;33m=\u001b[0m \u001b[0mentry\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_value\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 280\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 281\u001b[0m \u001b[0mvoltage_value\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mentry\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\parameters.py\u001b[0m in \u001b[0;36mget_value\u001b[1;34m(self, parameters)\u001b[0m\n\u001b[0;32m 220\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 221\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mget_value\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParameter\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 222\u001b[1;33m \u001b[0mvalue\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__get_value_internal\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 223\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__check_parameter_set_valid\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 224\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mParameterValueIllegalException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\parameters.py\u001b[0m in \u001b[0;36m__get_value_internal\u001b[1;34m(self, parameters)\u001b[0m\n\u001b[0;32m 241\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__get_value_internal\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParameter\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 242\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 243\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# float() wraps get_value for Parameters and works for normal floats also\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 244\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 245\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_value\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: float() argument must be a string or a number, not 'MeasurementDependentParameter'" + ] + } + ], + "source": [ + "first_sequence = sequencer.build()\n", + "print(first_sequence)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/06Branching.ipynb b/examples/06Branching.ipynb new file mode 100644 index 000000000..772dba8f8 --- /dev/null +++ b/examples/06Branching.ipynb @@ -0,0 +1,32 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Conditional Branching" + ] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/serialized_pulses/main b/examples/serialized_pulses/main new file mode 100644 index 000000000..36bd7336e --- /dev/null +++ b/examples/serialized_pulses/main @@ -0,0 +1,65 @@ +{ + "entries": [ + [ + 0, + 0, + "hold" + ], + [ + "ta", + "va", + "hold" + ], + [ + "tb", + "vb", + "linear" + ], + [ + "tend", + 0, + "jump" + ] + ], + "is_measurement_pulse": false, + "time_parameter_declarations": [ + { + "default_value": null, + "max_value": "tb", + "min_value": 0, + "name": "ta", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": "tend", + "min_value": "ta", + "name": "tb", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": Infinity, + "min_value": "tb", + "name": "tend", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ], + "type": "qctoolkit.pulses.table_pulse_template.TablePulseTemplate", + "voltage_parameter_declarations": [ + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "va", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "vb", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ] +} \ No newline at end of file diff --git a/examples/serialized_pulses/sequence_embedded b/examples/serialized_pulses/sequence_embedded new file mode 100644 index 000000000..d0d71498b --- /dev/null +++ b/examples/serialized_pulses/sequence_embedded @@ -0,0 +1,81 @@ +{ + "external_parameters": [], + "is_interruptable": true, + "subtemplates": [ + { + "mappings": { + "ta": "1", + "tb": "2", + "tend": "5", + "va": "5", + "vb": "0" + }, + "template": { + "entries": [ + [ + 0, + 0, + "hold" + ], + [ + "ta", + "va", + "hold" + ], + [ + "tb", + "vb", + "linear" + ], + [ + "tend", + 0, + "jump" + ] + ], + "is_measurement_pulse": false, + "time_parameter_declarations": [ + { + "default_value": null, + "max_value": "tb", + "min_value": 0, + "name": "ta", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": "tend", + "min_value": "ta", + "name": "tb", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": Infinity, + "min_value": "tb", + "name": "tend", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ], + "type": "qctoolkit.pulses.table_pulse_template.TablePulseTemplate", + "voltage_parameter_declarations": [ + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "va", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "vb", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ] + } + } + ], + "type": "qctoolkit.pulses.sequence_pulse_template.SequencePulseTemplate" +} \ No newline at end of file diff --git a/examples/serialized_pulses/sequence_referenced b/examples/serialized_pulses/sequence_referenced new file mode 100644 index 000000000..7d5e42fb9 --- /dev/null +++ b/examples/serialized_pulses/sequence_referenced @@ -0,0 +1,17 @@ +{ + "external_parameters": [], + "is_interruptable": true, + "subtemplates": [ + { + "mappings": { + "ta": "1", + "tb": "2", + "tend": "5", + "va": "5", + "vb": "0" + }, + "template": "table_template" + } + ], + "type": "qctoolkit.pulses.sequence_pulse_template.SequencePulseTemplate" +} \ No newline at end of file diff --git a/examples/serialized_pulses/stored_template b/examples/serialized_pulses/stored_template new file mode 100644 index 000000000..d8b6b63fb --- /dev/null +++ b/examples/serialized_pulses/stored_template @@ -0,0 +1,34 @@ +{ + "entries": [ + [ + 0, + 0, + "hold" + ], + [ + 4, + 20, + "linear" + ] + ], + "is_measurement_pulse": false, + "time_parameter_declarations": [ + { + "default_value": null, + "max_value": Infinity, + "min_value": 0, + "name": "4", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ], + "type": "qctoolkit.pulses.table_pulse_template.TablePulseTemplate", + "voltage_parameter_declarations": [ + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "20", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ] +} \ No newline at end of file diff --git a/examples/serialized_pulses/table_template b/examples/serialized_pulses/table_template new file mode 100644 index 000000000..36bd7336e --- /dev/null +++ b/examples/serialized_pulses/table_template @@ -0,0 +1,65 @@ +{ + "entries": [ + [ + 0, + 0, + "hold" + ], + [ + "ta", + "va", + "hold" + ], + [ + "tb", + "vb", + "linear" + ], + [ + "tend", + 0, + "jump" + ] + ], + "is_measurement_pulse": false, + "time_parameter_declarations": [ + { + "default_value": null, + "max_value": "tb", + "min_value": 0, + "name": "ta", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": "tend", + "min_value": "ta", + "name": "tb", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": Infinity, + "min_value": "tb", + "name": "tend", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ], + "type": "qctoolkit.pulses.table_pulse_template.TablePulseTemplate", + "voltage_parameter_declarations": [ + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "va", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + }, + { + "default_value": null, + "max_value": Infinity, + "min_value": -Infinity, + "name": "vb", + "type": "qctoolkit.pulses.parameters.ParameterDeclaration" + } + ] +} \ No newline at end of file From a65912d8edbeb802427ea604018424698a8cbc9d Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Sun, 27 Dec 2015 16:32:42 +0100 Subject: [PATCH 17/33] Progress on examples. --- examples/05Parameters.ipynb | 89 +++++++--- examples/06ConditionalExecution.ipynb | 168 ++++++++++++++++++ ...06Branching.ipynb => 07PulseControl.ipynb} | 11 +- examples/08RealWorldCase.ipynb | 41 +++++ 4 files changed, 282 insertions(+), 27 deletions(-) create mode 100644 examples/06ConditionalExecution.ipynb rename examples/{06Branching.ipynb => 07PulseControl.ipynb} (74%) create mode 100644 examples/08RealWorldCase.ipynb diff --git a/examples/05Parameters.ipynb b/examples/05Parameters.ipynb index a8c21a16f..7248b4aeb 100644 --- a/examples/05Parameters.ipynb +++ b/examples/05Parameters.ipynb @@ -6,6 +6,10 @@ "source": [ "# More Sophisticated Parameters\n", "\n", + "This example assumes that you are familiar with the sequencing process. If you need a refresher on this, have a look at [The Sequencing Process: Obtaining Pulse Instances From Pulse Templates](04Sequencing.ipynb) first.\n", + "\n", + "*Attention/Broken: During the creation of this example some implementation errors were found in the qctoolkit. Due to time constraints, these were not fixed immediately, leaving this example to be slightly flawed. However, in order to demonstrate the underlying principles, this example is published in its current form. Annotations like this mark where the current behavior of the qctoolit diverges from the intended one.*\n", + "\n", "So far we have only considered constant parameter values. Now assume that we need to derive the value for a parameter based on some measurements we've made during the execution of previous parts of a composite pulse. For example, let the pulse we want to execute be constructed as follows:" ] }, @@ -28,7 +32,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -72,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "collapsed": true }, @@ -80,7 +84,7 @@ "source": [ "from qctoolkit.pulses import Parameter\n", "\n", - "class MeasurementDependentParameter:\n", + "class MeasurementDependentParameter(Parameter):\n", " \n", " def __init__(self, measurement_manager) -> None:\n", " self.measurement_manager = measurement_manager\n", @@ -90,21 +94,28 @@ " return not self.measurement_manager.is_measurement_available()\n", " \n", " def get_value(self) -> float:\n", - " return 2*(self.measurement_manager.get_data())" + " return 2*(self.measurement_manager.get_data())\n", + " \n", + " def get_serialization_data(self, serializer):\n", + " raise NotImplementedError()\n", + " \n", + " @staticmethod\n", + " def deserialize(serializer):\n", + " raise NotImplementedError()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "We overwrite the abstract property `requires_stop` and the abstract method `get_value` of the `Parameter` base class. `requires_stop` is used to indicate to the `Sequencer` whether the `Parameter` object can currently be evaluated or whether the sequencing process has to be interrupted. Our `MeasurementDependentParameter` will return `True` if no measurement data is available (in contrast, the `ConstantParameter` - which internally represents any float value passed in - always returns `False`). The `get_value` method returns the parameter value. It is only called if `requires_stop` is false. In the `MesaurementDependentParameter` class, we assume that the measured data is a single float and that we simple want to multiply it by 2 as the parameter's value.\n", + "We overwrite the abstract property `requires_stop` and the abstract method `get_value` of the `Parameter` base class. `requires_stop` is used to indicate to the `Sequencer` whether the `Parameter` object can currently be evaluated or whether the sequencing process has to be interrupted. Our `MeasurementDependentParameter` will return `True` if no measurement data is available (in contrast, the `ConstantParameter` - which internally represents any float value passed in - always returns `False`). The `get_value` method returns the parameter value. It is only called if `requires_stop` is false. In the `MesaurementDependentParameter` class, we assume that the measured data is a single float and that we simple want to multiply it by 2 as the parameter's value. The other two methods, `get_serialization_data` and `deserialize` also must be overwritten since each `Parameter` implements the [`Serializable` interface](03Serialization.ipynb). However, we just raise an exception here since these methods are not relevant in this example.\n", "\n", "We would then set up our pulse for execution like as in the following snippet (including a stub implementation of a `MeasurementManager` just for demonstration purposes):" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 10, "metadata": { "collapsed": false }, @@ -113,16 +124,13 @@ "from qctoolkit.pulses import Sequencer\n", "\n", "# We define a stub for the measurement manager here only for illustration purposes.\n", - "# It will state that a measurement is available iff Sequencer has interrupted its operation\n", "class MeasurementManager:\n", " def __init__(self, sequencer: Sequencer) -> None:\n", " self.sequencer = sequencer\n", - " self.call_count = 0\n", + " self.is_available = False\n", " \n", " def is_measurement_available(self) -> bool:\n", - " is_available = self.call_count > 0\n", - " self.call_count += 1\n", - " return is_available\n", + " return self.is_available\n", " \n", " def get_data(self) -> float:\n", " return 3\n", @@ -141,7 +149,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "The `MeasurementManager.is_measurement_available` stub will simply return `False` in the first invocation of `Sequencer.build` and `True` iff the `Sequencer` was interrupted before, simulating that some data is measured during the execution of the first part of the pulse.\n", + "The `MeasurementManager.is_measurement_available` stub will simply return the value to which we have set the `is_available` member variable of the class.\n", + "\n", + "*Attention/Broken: Note that the subtemplates of the `sequence_template` defined above are pushed to the stack manually. Currently, `SequencePulseTemplate` is broken and will require a stop if any of the parameters used by any subtemplate return `True` via `requires_stop()`, resulting in an empty instruction sequence in any case. Needs fixing ([issue 104](https://github.com/qutech/qc-toolkit/issues/104))*\n", "\n", "When we invoke `Sequencer.build`, for each template on the sequencing stack it first queries whether or not all parameters can be evaluated. If any of them returns `True` via the `requires_stop` method, the sequencing process will be interrupted.\n", "In our example, `Sequencer` will first proceed through the first two subtemplates of `sequence_template`. When it arrives at `dependent_template`, it will stop:" @@ -149,25 +159,16 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 11, "metadata": { "collapsed": false }, "outputs": [ { - "ename": "TypeError", - "evalue": "float() argument must be a string or a number, not 'MeasurementDependentParameter'", - "output_type": "error", - "traceback": [ - "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", - "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m()\u001b[0m\n\u001b[1;32m----> 1\u001b[1;33m \u001b[0mfirst_sequence\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0msequencer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuild\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 2\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mfirst_sequence\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\sequencing.py\u001b[0m in \u001b[0;36mbuild\u001b[1;34m(self)\u001b[0m\n\u001b[0;32m 101\u001b[0m \u001b[0mshall_continue\u001b[0m \u001b[1;33m|=\u001b[0m \u001b[1;32mTrue\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 102\u001b[0m \u001b[0msequencing_stack\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mpop\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 103\u001b[1;33m \u001b[0melement\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbuild_sequence\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mconditions\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtarget_block\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 104\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;32mbreak\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\table_pulse_template.py\u001b[0m in \u001b[0;36mbuild_sequence\u001b[1;34m(self, sequencer, parameters, conditions, instruction_block)\u001b[0m\n\u001b[0;32m 314\u001b[0m \u001b[0mconditions\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mCondition\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 315\u001b[0m instruction_block: InstructionBlock) -> None:\n\u001b[1;32m--> 316\u001b[1;33m \u001b[0minstantiated\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_entries_instantiated\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 317\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0minstantiated\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 318\u001b[0m \u001b[0mwaveform\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mTableWaveform\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mtuple\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0minstantiated\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\table_pulse_template.py\u001b[0m in \u001b[0;36mget_entries_instantiated\u001b[1;34m(self, parameters)\u001b[0m\n\u001b[0;32m 277\u001b[0m \u001b[1;31m# resolve voltage parameter references only if voltageParameters argument is not None, otherwise they are irrelevant\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 278\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mentry\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParameterDeclaration\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 279\u001b[1;33m \u001b[0mvoltage_value\u001b[0m\u001b[1;33m=\u001b[0m \u001b[0mentry\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget_value\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 280\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 281\u001b[0m \u001b[0mvoltage_value\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mentry\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mv\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\parameters.py\u001b[0m in \u001b[0;36mget_value\u001b[1;34m(self, parameters)\u001b[0m\n\u001b[0;32m 220\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 221\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0mget_value\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParameter\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 222\u001b[1;33m \u001b[0mvalue\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__get_value_internal\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 223\u001b[0m \u001b[1;32mif\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m__check_parameter_set_valid\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 224\u001b[0m \u001b[1;32mraise\u001b[0m \u001b[0mParameterValueIllegalException\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mvalue\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;32mC:\\Anaconda3\\lib\\site-packages\\qctoolkit\\pulses\\parameters.py\u001b[0m in \u001b[0;36m__get_value_internal\u001b[1;34m(self, parameters)\u001b[0m\n\u001b[0;32m 241\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m__get_value_internal\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mparameters\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mDict\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mstr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mParameter\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 242\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 243\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mfloat\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mparameters\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mname\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;31m# float() wraps get_value for Parameters and works for normal floats also\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 244\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mKeyError\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 245\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdefault_value\u001b[0m \u001b[1;32mis\u001b[0m \u001b[1;32mnot\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", - "\u001b[1;31mTypeError\u001b[0m: float() argument must be a string or a number, not 'MeasurementDependentParameter'" + "name": "stdout", + "output_type": "stream", + "text": [ + "[, , ]\n" ] } ], @@ -176,6 +177,42 @@ "print(first_sequence)" ] }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see in the output above, only two executions instructions are generated, one for each `TablePulseTemplate` instance before the `dependent_template`. Let us now switch the `is_available` variable of the `MeasurementManager` instance to `True`, simulating that we've obtained some measurement result, and invoke the `Sequencer` again:" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, , , , ]\n" + ] + } + ], + "source": [ + "measurement_manager.is_available = True\n", + "second_sequence = sequencer.build()\n", + "print(second_sequence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have now obtained the complete sequence with one execution instruction for each `TablePulseTemplate`.\n", + "*Attention/Broken: Currently this is incorrect behavior: We would want to only get the remainder of the pulse in the second call since we wouldn't want to execute the first part of the pulse again. Needs fixing ([issue 105](https://github.com/qutech/qc-toolkit/issues/105)).*" + ] + }, { "cell_type": "code", "execution_count": null, diff --git a/examples/06ConditionalExecution.ipynb b/examples/06ConditionalExecution.ipynb new file mode 100644 index 000000000..aaa783b38 --- /dev/null +++ b/examples/06ConditionalExecution.ipynb @@ -0,0 +1,168 @@ +{ + "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": 4, + "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": 6, + "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": 8, + "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." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} diff --git a/examples/06Branching.ipynb b/examples/07PulseControl.ipynb similarity index 74% rename from examples/06Branching.ipynb rename to examples/07PulseControl.ipynb index 772dba8f8..13e46b3c1 100644 --- a/examples/06Branching.ipynb +++ b/examples/07PulseControl.ipynb @@ -4,8 +4,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Conditional Branching" + "# Pulse-Control Integration" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/examples/08RealWorldCase.ipynb b/examples/08RealWorldCase.ipynb new file mode 100644 index 000000000..6a0017be3 --- /dev/null +++ b/examples/08RealWorldCase.ipynb @@ -0,0 +1,41 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Gate Configuration - A Real Use Case" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] + } + ], + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} From 8cf0c797371e0318587e8ab8fd63a2bba830f43e Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Tue, 29 Dec 2015 17:46:02 +0100 Subject: [PATCH 18/33] Progress on examples: Small additions to 00SimpleTablePulse and 04Sequencing. Completed 08RealWorldCase. --- examples/00SimpleTablePulse.ipynb | 2 + examples/04Sequencing.ipynb | 8 +- examples/08RealWorldCase.ipynb | 350 ++++++++++++++++++++++++++++- examples/img/gate_pulse_scheme.svg | 172 ++++++++++++++ 4 files changed, 529 insertions(+), 3 deletions(-) create mode 100644 examples/img/gate_pulse_scheme.svg diff --git a/examples/00SimpleTablePulse.ipynb b/examples/00SimpleTablePulse.ipynb index 9caf3a6a2..9920ee21e 100644 --- a/examples/00SimpleTablePulse.ipynb +++ b/examples/00SimpleTablePulse.ipynb @@ -95,6 +95,8 @@ "source": [ "Alright, we got what we wanted. \n", "\n", + "Note that the time domain in pulse defintions does not correspond to any fixed real world time unit. The mapping from a single time unit in a pulse definition to real time in execution is made by setting a sample rate when converting the pulse templates to waveforms. For more on this, see [The Sequencing Process: Obtaining Pulse Instances From Pulse Templates](04Sequencing.ipynb).\n", + "\n", "## Introducing Parameters\n", "Now we want to make the template parameterizable. This allows us to reuse the template for pulses with similar structure. Say we would like to have the same pulse, but the intermediate linear interpolation part should last 4 units of time instead of only 2. Instead of creating another template with hardcoded values, we instruct the `TablePulseTemplate` instance to rely on parameters." ] diff --git a/examples/04Sequencing.ipynb b/examples/04Sequencing.ipynb index 4d63a4b39..6360552c7 100644 --- a/examples/04Sequencing.ipynb +++ b/examples/04Sequencing.ipynb @@ -107,7 +107,13 @@ "source": [ "Using the `push` method of `Sequencer`, we add `PulseTemplate` objects to the sequencing stack, i.e., the last pushed object will be sequenced first. We then invoke the `build` method to start the sequencing process, which will process all objects on the stack and return a sequence of hardware instructions. As you can see in the output of the above code snippet, the `Sequencer` created a sequence of two `EXECInstruction`s and a `STOPInstruction`. The two `EXECInstruction`s refer to waveforms obtained by sampling the atomic template objects `table_template` and `function_template` of which the `sequence_template` we've sequenced is composed.\n", "\n", - "The instruction sequence will afterwards be passed to a hardware-dependent interpreter which will configure the corresponding device accordingly. Note that the `plot` function internally employs sequencing and then simply plots the generated waveforms.\n", + "These waveforms are represented by objects of the `Waveform` class, which exposes a method `sample`, accepting an array of sample points in the time domain and returning an equally long array of sample values. The choice of the sample points passed into the `sample` method together with the sample rate of the playback device determine the duration of a time unit in a pulse template. For example, a pulse template with a length of 1 time unit that is sampled using 1000 equidistant sample points will play for 1 µs on a playback device with a sample rate of 1 GHz.\n", + "\n", + "After the sequencing process is complete, the instruction sequence will be passed to a hardware-dependent interpreter which will configure the corresponding device accordingly and perform the sampling of the waveform depending on the device's sample rate and typically a parameter indicating the real-time duration of a pulse template time unit.\n", + "\n", + "\n", + "\n", + "Note that the `plot` function internally employs sequencing and then simply plots the generated waveforms.\n", "\n", "## Side Note: Instructions\n", "\n", diff --git a/examples/08RealWorldCase.ipynb b/examples/08RealWorldCase.ipynb index 6a0017be3..e00314d32 100644 --- a/examples/08RealWorldCase.ipynb +++ b/examples/08RealWorldCase.ipynb @@ -7,14 +7,360 @@ "# Gate Configuration - A Real Use Case" ] }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "An example for a real use case of the qctoolkit is the search for / evaluation of parameters for pulses that represent quantum gate operations.\n", + "\n", + "## Description of the Experiment\n", + "The experiment will typically involve a set of gate pulses $G_j, 0 \\leq j \\lt N_{Gates}$.\n", + "\n", + "The template for a gate pulse $G_j$ is a sequence of $\\epsilon_i, 0 \\leq i \\lt N_{G_j}$ voltage levels held for time $\\Delta t = 1$ ns as illustrated in the figure below (with $N_{G_j} = 7$).\n", + "\n", + "\"Template\n", + "\n", + "The experiment defines a number of sequences $S_k, 0 \\leq k \\lt N_{Sequences}$ of the $G_j$ as $$S_k = (G_{m_k(1)}, G_{m_k(2)}, \\dots, G_{m_k(N_{S_k})})$$ where $S_k$ is the length of sequence $k$ and $m_k(i): \\{0, \\dots, N_{S_k} - 1\\} \\rightarrow \\{0, \\dots, N_{Gates} - 1\\}$ is a function that maps an index $i$ to the $i$-th gate of sequence $S_k$ and thus fully describes the sequence. (These sequences express the sequential application of the gates to the qubit. In terms of quantum mathematics the may rather be expressed as multiplication of the matrices describing the unitary transformations applied by the gates: $S_k = \\prod_{i=0}^{N_{S_k} - 1} G_{m_k(i)}$.)\n", + "\n", + "Measuring and analysing the effects of these sequences on the qubit's state to derive parameters $\\epsilon_i$ for gate pulses that achieve certain state transformations is the goal of the experiment.\n", + "\n", + "To this end, every sequence must be extended by some preceeding initialization pulse and a succeeding measurement pulse. Furthermore, due to hardware constraints in measuring, all sequences must be of equal length (which is typically 4 µs). Thus, some sequences require some wait time after initialization to increase their playback duration. These requirements give raise to extended sequences $S_k'$ of the form:\n", + "$$S_k' = I_{p(k)} | W_k | S_k | M_{q(k)}$$\n", + "where the functions $p(k)$ and $q(k)$ respectively select some initialization pulse $I_{p(k)} \\in \\{I_1, I_2, \\dots\\}$ and measurement pulse $M_{q(k)} \\in \\{M_1, M_2, \\dots\\}$ for sequence $k$ and $W_k$ is the aforementioned wait pulse. The '|' denote concatenation.\n", + "\n", + "Since measurement of quantum state is a probabilistic process, many measurements of the effect of a single sequence must be made to reconstruct the resulting state of the qubit. Thus, the experiment at last defines scanlines (typically of duration 1 second), which are sequences of the $S_k'$. (These simply represent batches of sequences to configure playback and measurement systems and have no meaning to the experiment beyond these practical considerations.)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implementation Using the qctoolkit\n", + "\n", + "We now want to illustrate how to setup the experiment described above using the qctoolkit. Let us assume the experiment considers only two different gates pulses ($N_{Gates} = 2$). We further assume that $N_{G_1} = 20$ and $N_{G_2} = 18$. We define them using instances of `TablePulseTemplate`:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import TablePulseTemplate\n", + "\n", + "delta_t = 1 # assuming that delta_t is 1 elementary time unit long in pulse defintions, i.e. 1 time unit = 1 ns\n", + "\n", + "gate_0 = TablePulseTemplate()\n", + "for i in range(0, 19):\n", + " gate_0.add_entry((i) * delta_t, 'gate_0_eps_' + str(i))\n", + " \n", + "gate_1 = TablePulseTemplate()\n", + "for i in range(0, 17):\n", + " gate_1.add_entry((i) * delta_t, 'gate_1_eps_' + str(i))\n", + " \n", + "gates = [gate_0, gate_1]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We thus obtain two `TablePulseTemplate` of the desired form with parameters 'gate_1_eps_1' to 'gate_1_eps_20' and 'gate_2_eps_1' to 'gate_2_eps_18'.\n", + "\n", + "Next, we will define sequences as `SequncePulseTemplate` objects. We assume that the mapping functions $m_k$ are given as a 2 dimensional array (which impilicitly also defines $N_{Sequences}$ and $N_{S_k}$), e.g.:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "m = [\n", + " [0, 1, 0, 0, 0, 1, 1, 0, 1], # m_0(i)\n", + " [1, 1, 0, 0, 1, 0], # m_1(i)\n", + " [1, 0, 0, 1, 1, 0, 0, 1] #m_2(i)\n", + " ]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `SequencePulseTemplate` objects can now easily be constructed:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import SequencePulseTemplate\n", + "\n", + "# SequencePulseTemplate requires a definition of parameter mappings from parameters passed into the\n", + "# SequencePulseTemplate object to its subtemplates. In this case, we want parameters to map 1 to 1\n", + "# and thus create an identity mapping of parameter names for both gates using python list/set/dict comprehension\n", + "epsilon_mappings = [\n", + " {param_name: param_name for param_name in gates[0].parameter_names},\n", + " {param_name: param_name for param_name in gates[1].parameter_names}\n", + "]\n", + "all_epsilons = gates[0].parameter_names | gates[1].parameter_names\n", + "\n", + "sequences = []\n", + "for m_k in m:\n", + " subtemplates = []\n", + " for g_ki in m_k:\n", + " subtemplates.append((gates[g_ki], epsilon_mappings[g_ki]))\n", + " sequences.append(SequencePulseTemplate(subtemplates, all_epsilons))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We end up with a list `sequences` which contains the sequences described by our $m$ as qctoolkit pulse templates.\n", + "\n", + "To visualize our progress, let us plot our two gates and the second sequence with some random values between $-5$ and $5$ for the $\\epsilon_i$:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false, + "scrolled": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\nr9d0TGtrm9s5sx73GOMVU74egBfPlZMAzQhugGYEN0Azghu4xRwz11Qle3tLH8luMgMOTLS3N88s\nLWsKuTlmruHsCG6Y6MqV268DczJUAtCM4AZoZhVDJXPN4rymMUKAs7KK4PZHEIDTM1QC0IzgBmhG\ncAM0I7gBmhHcAM0IboBmBDdAM4IboBnBDdCM4AZoRnADNCO4OVdzzayyv7/0kcByVnGTKc7WnDO0\nTJ00YK6ZVea6oyR0JLgvgLlmaBGWsA6GSgCaEdwAzQhugGYEN0AzghugGcEN0IzgBmhGcAM0I7gB\nmpkc3FX1q1X1QlW5ewTAOZgU3FV1Kcnrkvz7POUAcDtTe9zvSfLrcxQCwOnccXBX1UNJnh1jfGrG\negC4jRPvDlhVjyW594i33p3kXUlef+PqM9YFwDFODO4xxuuOer2qvi/Jy5M8Udfu9Xlfkk9U1QNj\njOdvXv/g4OD68mazyWazufOKAXbQdrvNdrs91bo1ZrirfVV9IckPjDFuufNzVY059sHyqqZPgjDH\nNta4nbXYxXbZxWM6jarKGOPIkYy5zuNu1BwAvc0yA84Y47vn2A4At+fKSYBmzDnJqc0x6fDe3jy1\nwEUmuDm1uSYdBqYR3LBD5vhf0Ve3w3rNcjrgiTtwOiBn4KKeInYRXdTv9UmnA+px05KeJReZHjew\nanrct3I6IEAzghugGWPcwKr5e8atjHEDrJAxboAdIrgBmhHcAM0IboBmBDdAM6sI7tPOs8ad0b5n\nS/ueLe17K8F9AWjfs6V9z5b2vdUqghuA0xPcAM2cy5WTZ7oDgB113JWTZx7cAMzLUAlAM4IboJnF\ng7uqLlfVZ6vqqap659L17JqqerqqPlVVj1fVx5aup7uq+sOqeq6qPn3Da/tV9VhVfa6qHq2qb1+y\nxs6Oad+Dqnr28DP8eFVdXrLGNVg0uKvqriTvTXI5yauSvLmqXrlkTTtoJNmMMe4fYzywdDE74I9y\n7fN6o99I8tgY43uS/MPhc+7MUe07krzn8DN8/xjj7xaoa1WW7nE/kOTzY4ynxxhfTvKBJA8tXNMu\nmuE29CTJGOOfkly96eU3Jnn/4fL7k7zpXIvaIce0b+Iz/DWWDu6XJnnmhufPHr7GfEaSv6+qj1fV\nW5cuZkfdM8Z47nD5uST3LFnMjvrlqnqiqh4xFLV8cDsX8ey9Zoxxf5IfTfJLVfXDSxe0yw6ne/K5\nntcfJHl5klcn+VKS3122nOUtHdxfTHLphueXcq3XzUzGGF86/Pe/knww14anmNdzVXVvklTVdyZ5\nfuF6dsoY4/lxKMn74jO8eHB/PMkrquplVfWSJD+V5EML17Qzquobq+pbDpe/Kcnrk3z65K/iDnwo\nyVsOl9+S5K8WrGXnHP4y/KqfiM/wsrO8jzG+UlVvS/KRJHcleWSM8eSSNe2Ye5J8sK5NkX13kj8Z\nYzy6bEm9VdWfJXkwyXdU1TNJfivJbyf586r6+SRPJ/nJ5Srs7Yj2fTjJpqpenWtDUF9I8gsLlrgK\nLnkHaGbpoRIAXiTBDdCM4AZoRnADNCO4AZoR3ADNCG6AZgQ3QDP/B4Xc1ikAa/yhAAAAAElFTkSu\nQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\nRK5CYII=\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "image/png": "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\n0UGDsnsdM9i+PRqju3Z1jPcu2ztTDwC2NGpvBc7J8jWlQIwYAfPnRzPtNEyzlUb/9E9Npw077bTk\napH2GzIEFiyIZqC59VYYMCDRkvIi2+B2sVQRE+f8BKwNDj/c/0UOVdL9OewwuPTS/K0vScOG+Ycc\nnKTHqJk/LNjRZBvcFUDj/+wMwu91N1FSUvLZcmVlBshkudqWff3r8MwzPnDq6uD+++Ff/iUnq8qL\nm2/28xE29Ofb34Z//dekqxKJ3HlndGiprg7uuQd+8IOkqwpTaWkppaWl7XputsG9BBhuZkOAbcBV\nwJTmT2oc3HPmwLp1Wa61FVVV/oTcP/4jPPYYrFmTm/XkS1WVP2F65ZUwd65mAJfCU10NP/0pTJvm\nd5r+8IekKwpXJpMhk8l81p49e3arz80quJ1z+8zsduA3wOHAMyFdUSIiEqKsp811zv038N8x1CIi\nIu3QAS6cERFJFwW3iEhgFNwiIoFRcIuIBEbBLSISGAW3iEhgFNwiIoFRcIuIBEbBLSISGAW3iEhg\nFNwiIoFRcIuIBEbBLSISmKzvDihSaLZvh40b/fJ77yVbSy45B3/8YzS1XMP0XVL4du6EDRv88vr1\nB//zeQnu55+PJjWYNw8a3Ss8p7ZsgVdegc2b43/tF16AtWvhf/8XBg+O//Vb0tCf99/Pz/pCde+9\n8NZb0fyYN9yQbD25smkTjB8PZ5zh26eeCkcdFX1/4UI/9pcsgT598lNTRYUfo9u25Wd9oZo5E954\nA4491renTTu4n89LcNfUwJ49fnnyZPjSl3K/zrFj/cB96CHfjnOdX/sa/O53vk+nnZafeRnHjPGT\nouaiP2mzf7+f/HfK5+ZiSpf9+/0s6S3NOnPDDfDaa36Mjh4NEybkvp7Ro+G556Ix+nd/l/t1hmr/\nfnjwQZg+/dB+Pi/Bfc01+VhLU+ef7//y58KECfn5RWhs/Pjc9UfS56KL/COfzjlHYzRfdHJSRCQw\nCm4RkcAouEVEAqPgFhEJjIJbRCQwCm4RkcAouEVEAqPgFhEJjIJbRCQwCm4RkcDo7oASJOf8Tb4a\n7ozXtSuMGJFsTblSVeVvMNZg8GDo1Su5eqT91q6N7trYpQucdFI8r6vgPoDKSqit9ct1dcnWEofG\n/dm/P9lasrVpk7+RWMMvQlmZv51rvu6Cl0933w2vvgq9e8Pu3f5GbXPnJl1VbqRpjG7d6m+8NXKk\nb5eX+7s1DhiQ/WsruFvx3ns+FI4+2rePPBK6d0+2pmxs2gTDh0f96dEDjjgi2ZqyUVsLQ4bAypW+\n3a9f9AufNrW1/o57114LTz0Fb7+ddEW5UVHh/zfRMEa7dIGePZOtKRu1tTBwYDRGhwyJb4wquFux\nZ48P7tWrk64kHnv2+OAuL0+6EpGW7dnjgzvNk1/EpUMGd3FxdANzgJtuSq6WOBQXQ9++UfvGG5Or\nRaQlxcVw/PFR+6qrkqslDTpkcDfMxtPALJk64lJW1rQden8kfZYvb9rWGM1OhwzutA2atPVH0kdj\nNF5ZXcdtZt83s3IzW2FmC8xMFymJiORYth/A+S1winNuLLAOmJl9SSIiciBZBbdzbpFzruEK57eA\ngdmXJCIiBxLnR95vAF6O8fVERKQFbZ6cNLNFQN8WvnW/c+5X9c95AKhxzv2ipdcoKSn5bDmTyZDJ\nZA6lVhGR1CotLaW0tLRdz20zuJ1zlxzo+2Y2HZgE/G1rz2kc3CIi8nnNd2pnz57d6nOzuhzQzCYC\n9wEXOOf2ZPNaIiLSPtke454D9AAWmdkyM0vprW9ERApHVnvczrnhcRUiIiLto4kUREQCo+AWEQlM\nh7xXiYSppsbPKAL+/uJpVlHhJxUAqK5OthZpv9ra6CZ2W7fmbj0Kbklc587+Hswnnujbu3b5rzX3\n85/DvfdGM4h84Qv5qzEunTvDPffArFnw8cdw5ZUtP2/cOD8dW1GRv0HT0KH5rVOa6tzZTx/XMEYr\nKloeo7/8Jdxxh59AAeDcc3NTj4JbEnfCCT64G88f2TALSmO1tfCVr8CTT+a3vjjNmQMPPBC1+/dv\n+Xm1tfD738czzZVkb8AA/7+8xvNH9uv3+efV1sIVV8BPfpLbehTcUhAa32Q/zXr0iPbaJCyDBiVd\nQUQnJ0VEAqM9bgFg3z7/37zQZ9Zui3PRhK3OJVuLHJyGMbpvX9KVJK9g97i/8x3/X8oTT4SSkpZP\nBISkpCTqz6xZhdWfY4+F6dP9LPZ33w3HHJN0RbnRs6c/qdS9u3988on/V7zvfjcaozNnFtYYPeYY\nPzds9+5w221N54ztiAp2j7usDGbMgEsv9e3WTtIUFcF550GnTv6s77Rp+avxYJSVwZ13wqRJvt3a\nSamiIhg/3vdn61aYMiX3tc2Z4x9p17+/D2tpWXk53HyzP7kGBx6jF13k/62ogMsuy31tDz/sH+IV\nbHCDP2vb1omcJUv8ZVXgL5saMSL3dR2qvn3b7s8770TX7RZ6fyR92jNGf/97qKryy2YwXDe+yLuC\nDu72GDAgXZdM9e/f+p6OSCHo16/lS+Ekfwr2GLeIiLRMwS0iEpjgD5XEbdUq/8m8bduSriQeq1f7\n/nz4YdKViLRszRo/RnftSrqScBTUHveIEf5khxm88AL07p3f9Z9/Ppx8MixdCtu3+zPs2Tj55Kg/\n8+fnvz/jx8PIkb4/H34It9yS3/VL4Rs7Nhqjzz6b/zF67rkwerQfo1u2+Ev9pG0FtcddWen/6vbp\nk8z6x4yJ9z4YlZWwY0dy15yeemrY9/WQ3Nu92wdmw02R8m3UKI3RQ1FQe9wiItI2BbeISGAU3CIi\ngVFwS0595Sv+BNjYsXDaafDWW0lXlBuvvx71c+xYf+8XCcO11zZ97xYvTrqithXUyUkJ1/Ll8P3v\n++UTT4S//3u//Oab/mqFPn3gm9/0N6M/55zk6ozD3LnQq5e/EmPqVP8x8fXrfb+/8x3YvBnuuy/p\nKqW5d9+NxugJJ8A//INfXrwYnnjCf2L5wQf9pB7jxydXZ3toj1uyduGF/lLKnTv9jYpmzmz6/VNO\n8Xsy+b7ULBcefNDPgrJzJzzzDLz2WvS9o4/2/Rw5Mrn6pGUXXACZjH/f1q37/B/WUaP8e1dcnEh5\nB0173JK1k06K9mTWrInuLpdGt94aLVdUJFeHHJxhw6IxunEjvPpqsvVkS3vcIiKBUXCLiARGwS0i\nEhgFt4hIYBTcIiKBUXCLiARGwS0iEhgFt4hIYBTcIiKByTq4zewbZlZnZoF8WFREJGxZBbeZDQIu\nAd6PpxwREWlLtnvc/w/4ZhyFiIhI+xxycJvZZGCrc25ljPWIiEgbDnh3QDNbBPRt4VsPADOBCY2f\nHmNdIiLSigMGt3Pukpa+bmajgaHACjMDGAj80czOds7tbP78kpKSz5YzmQyZTObQKxYRSaHS0lJK\nS0vb9dxDuh+3c24VcFxD28w2AWc65ypben7j4BYRkc9rvlM7e/bsVp8b13XcLqbXERGRNsQyA45z\n7oQ4XkdERNqmqcskdjU1sGGDX963L9lacm37dt/XnZ87syOFrLY2GqO1tcnWcigU3BKr4mLo2hUm\nTvTtfv2gR49ka8qVUaP8jO9z5/p24/kopXAddRQceWQ0Rnv3hl69kq3pYCm4JVbHHgtlZfG93hFH\nwI03wi23+NnVCykcH3zQP+LQrRts2uRDBeCTT/wfQIlfcTGsXh3f6/Xo4cfnjBl+jN54Y3yv3RoF\ntxS0J56AH/wgavfsmVwtuTRwIFRXR4eWior8Hy0pfD/6EXz3u1E7H//DVHBLXu3YAe+9B7t2te/5\nnTpFe6Ehqanx/YT2H+dP6yGl0DSM0faet0hijCq4JW9GjoRHH/UPgNtvT7aeXOnd2x/6mFD/ueI+\nfdL7P4W0OflkePJJ/wD4+teTrac1Cm7Jm1mz/CPtjjkGysuTrkIOxcyZ/lHoEg/uTz+FFSv8chou\nHduzJ+pPiJcZSfrt3RuN0ZqaZGuRQ5NocPfp4/9bed11vj1yZNgnZJr35+STddwyn379a7/9P/gg\n6Upya+NGeP55+PDDg//Z4mLo2zcao0OHhncpXMheftlfebV5c3avk2hw9+0LS5YkWUG8jjsuXf0J\nyXXXwW9+45f794cxY5KtJ1fOPNP3c948377mmoP7+eJieOed+OuStk2dCq+95pf79IHTTz/01zLn\ncnubETNzuV6HiEjamBnOuRZvl63JgkVEAqPgFhEJjIJbRCQwCm4RkcAouEVEApO34G7vXGpppm2g\nbQDaBqBtANltAwV3HmkbaBuAtgFoG0AgwS0iIvFQcIuIBCYvn5zM6QpERFKqtU9O5jy4RUQkXjpU\nIiISGAW3iEhgch7cZjbRzNaY2Xoz+1au11cIzGyQmb1uZqvNbJWZ3Vn/9WIzW2Rm68zst2YW4GyK\nB8fMDjezZWb2q/p2h9oGZnaUmT1vZuVmVmZm53TAbTCz/nfhXTP7hZl1Sfs2MLN/N7MdZvZuo6+1\n2uf6bbS+PisntPX6OQ1uMzsceAyYCIwCppjZyFyus0DUAnc7504BvgDcVt/vbwOLnHMjgFfr22k3\nAygDGk6mdLRt8CPgZefcSGAMsIYOtA3MbAjwNeAM59ypwOHA1aR/G/wEn3uNtdhnMxsFXIXPyInA\nXDM7YDbneo/7bGCDc26zc64WmAdMzvE6E+ec2+6cW16//BegHBgAXA78tP5pPwWuSKbC/DCzgcAk\n4Gmg4ex4h9kGZtYLON859+8Azrl9zrmP6UDbAPgTfkemu5l1AroD20j5NnDOvQlUNftya32eDDzn\nnKt1zm0GNuCzs1W5Du4BwJZG7a31X+sw6vc4TgfeAo5zzu2o/9YO4LiEysqXHwL3AXWNvtaRtsFQ\nYJeZ/cTMlprZU2Z2BB1oGzjnKoGHgQ/wgV3tnFtEB9oGjbTW5/74bGzQZk7mOrg79LWGZtYDeAGY\n4Zz7c+Pv1U8LlNrtY2aXATudc8uI9rabSPs2wE8NeAYw1zl3BvAJzQ4JpH0bmNkw4C5gCD6gepjZ\n1MbPSfs2aEk7+nzA7ZHr4K4ABjVqD6LpX5bUMrMifGj/zDm3sP7LO8ysb/33+wE7k6ovD84DLjez\nTcBzwEVm9jM61jbYCmx1zjXM8vg8Psi3d6BtcBbwB+fcbufcPmABcC4daxs0aG3sN8/JgfVfa1Wu\ng3sJMNzMhphZZ/wB+JdyvM7EmZkBzwBlzrlHGn3rJeCr9ctfBRY2/9m0cM7d75wb5Jwbij8Z9Zpz\nbhodaxtsB7aY2Yj6L10MrAZ+RQfZBviTsV8ws271vxcX409Wd6Rt0KC1sf8ScLWZdTazocBw4O0D\nvpJzLqcP4FJgLf6A+8xcr68QHsB4/HHd5cCy+sdEoBh4BVgH/BY4Kula87Q9LgBeql/uUNsAGAu8\nA6zA72326oDb4Jv4P1jv4k/KFaV9G+D/l7kNqMGf57v+QH0G7q/PyDXAF9t6fX3kXUQkMPrkpIhI\nYBTcIiKBUXCLiARGwS0iEhgFt4hIYBTcIiKBUXCLiARGwS0iEpj/Ayjpw6JZ8zdsAAAAAElFTkSu\nQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import random\n", + "\n", + "random.seed('Some seed such that numbers generated are predictable')\n", + "parameters = {parameter_name: random.random() * 10 - 5 for parameter_name in all_epsilons}\n", + "\n", + "%matplotlib inline\n", + "from qctoolkit.pulses import plot\n", + "plot(gates[0], parameters)\n", + "plot(gates[1], parameters)\n", + "plot(sequences[1], parameters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We now must construct the $S_k'$. For simplicity, we assume that there is only one initialization and one measurement pulse which are defined somehow and define only stubs here. We also define a waiting pulse with a variable length:" + ] + }, { "cell_type": "code", - "execution_count": null, + "execution_count": 5, "metadata": { "collapsed": true }, "outputs": [], - "source": [] + "source": [ + "# stub for an initialization pulse of length 4\n", + "init = TablePulseTemplate()\n", + "init.add_entry(0, 5)\n", + "init.add_entry(4, 0, 'linear')\n", + "\n", + "# stub for a measurement pulse of length 12\n", + "measure = TablePulseTemplate()\n", + "measure.add_entry(0, 0)\n", + "measure.add_entry(12, 5, 'linear')\n", + "\n", + "# a wating pulse\n", + "wait = TablePulseTemplate()\n", + "wait.add_entry('wait_duration', 0)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "For our example, let us assume that we want all $S_k'$ to take 200 ns (since we've chosen the $S_k$ to be rather short). We know that the duration of our gate pulses in nanoseconds is equal to the number of entries in the `TablePulseTemplate` objects (each voltage level is held for one unit of time in the tables which corresponds to $\\Delta t = 1$ ns). Accordingly, the init pulse lasts for 4 ns and the measure pulse for 12 ns. The required length of the wait pulse can then be computed as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[21, 76, 40]\n" + ] + } + ], + "source": [ + "wait_times = []\n", + "desired_time = 200\n", + "\n", + "for m_k in m:\n", + " duration_k = 4 + 12 # init + measurement duration\n", + " for g_ki in m_k:\n", + " duration_k += len(gates[g_ki].entries) # add the number of entries of all gates in the sequence\n", + " wait_time_k = desired_time - duration_k\n", + " wait_times.append(wait_time_k)\n", + " \n", + "print(wait_times)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally we can construct the $S_k'$:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# an identity mapping for all epsilons\n", + "all_epsilons_map = {param_name: param_name for param_name in all_epsilons}\n", + "\n", + "final_sequences = []\n", + "for k in range(0, len(sequences)):\n", + " \n", + " #prepare the subtemplate of the sequence S_k'\n", + " subtemplates = []\n", + " subtemplates.append((init, {})) # append the init pulse first\n", + " \n", + " # append the wait pulse next. pass in the appropriate wait time.\n", + " # note that the wait time has to be cast to a string. In parameter mappings, some string containing a mathematical\n", + " # expression is expected. Here, we provide a mathematical expression consisting only of a constant value.\n", + " subtemplates.append((wait, {'wait_duration': str(wait_times[k])}))\n", + " \n", + " # append the k-th sequence\n", + " subtemplates.append((sequences[k], all_epsilons_map))\n", + " \n", + " # append the measuring\n", + " subtemplates.append((measure, {}))\n", + " \n", + " # construct the object for S_k'\n", + " s_k_prime = SequencePulseTemplate(subtemplates, all_epsilons)\n", + " final_sequences.append(s_k_prime)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let us plot $S_1'$ to see what whether we've accomplished our goal:" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", + " \"matplotlib is currently using a non-GUI backend, \"\n" + ] + }, + { + "data": { + "image/png": "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\nuEVEEub/AVoWuOjZjxMYAAAAAElFTkSuQmCC\n", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "plot(final_sequences[1], parameters)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Finally, we construct a single scanline which just repeats all three sequences over and over again. Since our $S_k'$ are short, we just build a scanline with a duration of 0.6 microseconds. With a duration for each $S_k'$ of 200 ns, we can fit 1'000 repetitions of $S_1' | S_2' | S_3'$ in our scanline. " + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import Sequencer\n", + "\n", + "subtemplates = []\n", + "for i in range(0, 1000):\n", + " subtemplates.append((final_sequences[0], all_epsilons_map))\n", + " subtemplates.append((final_sequences[1], all_epsilons_map))\n", + " subtemplates.append((final_sequences[2], all_epsilons_map))\n", + " \n", + "scanline = SequencePulseTemplate(subtemplates, all_epsilons)" + ] } ], "metadata": { diff --git a/examples/img/gate_pulse_scheme.svg b/examples/img/gate_pulse_scheme.svg new file mode 100644 index 000000000..34214b2a3 --- /dev/null +++ b/examples/img/gate_pulse_scheme.svg @@ -0,0 +1,172 @@ + + + + + + + + + + image/svg+xml + + + + + + + ϵ1 + ϵ2 + + + ϵ3 + ϵ4 + ϵ5 + ϵ6 + ϵ7 + + From 7d9ee2d79011153600de574d90ea10a70da00f5c Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 8 Apr 2016 10:33:34 +0200 Subject: [PATCH 19/33] Corrections for jupyter-notebook example 8. --- examples/08RealWorldCase.ipynb | 57 ++++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 23 deletions(-) diff --git a/examples/08RealWorldCase.ipynb b/examples/08RealWorldCase.ipynb index e00314d32..f4b80f54f 100644 --- a/examples/08RealWorldCase.ipynb +++ b/examples/08RealWorldCase.ipynb @@ -13,7 +13,7 @@ "collapsed": true }, "source": [ - "An example for a real use case of the qctoolkit is the search for / evaluation of parameters for pulses that represent quantum gate operations.\n", + "An example for a real use case of the qctoolkit is the search for and evaluation of parameters for pulses that represent quantum gate operations.\n", "\n", "## Description of the Experiment\n", "The experiment will typically involve a set of gate pulses $G_j, 0 \\leq j \\lt N_{Gates}$.\n", @@ -22,13 +22,13 @@ "\n", "\"Template\n", "\n", - "The experiment defines a number of sequences $S_k, 0 \\leq k \\lt N_{Sequences}$ of the $G_j$ as $$S_k = (G_{m_k(1)}, G_{m_k(2)}, \\dots, G_{m_k(N_{S_k})})$$ where $S_k$ is the length of sequence $k$ and $m_k(i): \\{0, \\dots, N_{S_k} - 1\\} \\rightarrow \\{0, \\dots, N_{Gates} - 1\\}$ is a function that maps an index $i$ to the $i$-th gate of sequence $S_k$ and thus fully describes the sequence. (These sequences express the sequential application of the gates to the qubit. In terms of quantum mathematics the may rather be expressed as multiplication of the matrices describing the unitary transformations applied by the gates: $S_k = \\prod_{i=0}^{N_{S_k} - 1} G_{m_k(i)}$.)\n", + "The experiment defines a number of sequences $S_k, 0 \\leq k \\lt N_{Sequences}$ of the $G_j$ as $$S_k = (G_{m_k(1)}, G_{m_k(2)}, \\dots, G_{m_k(N_{S_k})})$$ where $N_{S_k}$ is the length of sequence $k$ and $m_k(i): \\{0, \\dots, N_{S_k} - 1\\} \\rightarrow \\{0, \\dots, N_{Gates} - 1\\}$ is a function that maps an index $i$ to the $m_k(i)$-th gate of sequence $S_k$ and thus fully describes the sequence. (These sequences express the sequential application of the gates to the qubit. In terms of quantum mathematics they may rather be expressed as multiplication of the matrices describing the unitary transformations applied by the gates: $S_k = \\prod_{i=N_{S_k} - 1}^{0} G_{m_k(i)} = G_{(N_{S_k} - 1)} \\cdot \\dots \\cdot G_{1} \\cdot G_{0}$.)\n", "\n", "Measuring and analysing the effects of these sequences on the qubit's state to derive parameters $\\epsilon_i$ for gate pulses that achieve certain state transformations is the goal of the experiment.\n", "\n", - "To this end, every sequence must be extended by some preceeding initialization pulse and a succeeding measurement pulse. Furthermore, due to hardware constraints in measuring, all sequences must be of equal length (which is typically 4 µs). Thus, some sequences require some wait time after initialization to increase their playback duration. These requirements give raise to extended sequences $S_k'$ of the form:\n", + "To this end, every sequence must be extended by some preceeding initialization pulse and a succeeding measurement pulse. Furthermore, due to hardware constraints in measuring, all sequences must be of equal length (which is typically 4 µs). Thus, some sequences require some wait time before initialization to increase their playback duration. These requirements give raise to extended sequences $S_k'$ of the form:\n", "$$S_k' = I_{p(k)} | W_k | S_k | M_{q(k)}$$\n", - "where the functions $p(k)$ and $q(k)$ respectively select some initialization pulse $I_{p(k)} \\in \\{I_1, I_2, \\dots\\}$ and measurement pulse $M_{q(k)} \\in \\{M_1, M_2, \\dots\\}$ for sequence $k$ and $W_k$ is the aforementioned wait pulse. The '|' denote concatenation.\n", + "where the functions $p(k)$ and $q(k)$ respectively select some initialization pulse $I_{p(k)} \\in \\{I_1, I_2, \\dots\\}$ and measurement pulse $M_{q(k)} \\in \\{M_1, M_2, \\dots\\}$ for sequence $k$ and $W_k$ is the aforementioned wait pulse. The '|' denote concatenation of pulses, i.e., sequential execution.\n", "\n", "Since measurement of quantum state is a probabilistic process, many measurements of the effect of a single sequence must be made to reconstruct the resulting state of the qubit. Thus, the experiment at last defines scanlines (typically of duration 1 second), which are sequences of the $S_k'$. (These simply represent batches of sequences to configure playback and measurement systems and have no meaning to the experiment beyond these practical considerations.)" ] @@ -44,7 +44,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -76,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": { "collapsed": true }, @@ -98,7 +98,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": { "collapsed": false }, @@ -134,7 +134,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 17, "metadata": { "collapsed": false, "scrolled": false @@ -150,9 +150,9 @@ }, { "data": { - "image/png": "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\nr9d0TGtrm9s5sx73GOMVU74egBfPlZMAzQhugGYEN0Azghu4xRwz11Qle3tLH8luMgMOTLS3N88s\nLWsKuTlmruHsCG6Y6MqV268DczJUAtCM4AZoZhVDJXPN4rymMUKAs7KK4PZHEIDTM1QC0IzgBmhG\ncAM0I7gBmhHcAM0IboBmBDdAM4IboBnBDdCM4AZoRnADNCO4OVdzzayyv7/0kcByVnGTKc7WnDO0\nTJ00YK6ZVea6oyR0JLgvgLlmaBGWsA6GSgCaEdwAzQhugGYEN0AzghugGcEN0IzgBmhGcAM0I7gB\nmpkc3FX1q1X1QlW5ewTAOZgU3FV1Kcnrkvz7POUAcDtTe9zvSfLrcxQCwOnccXBX1UNJnh1jfGrG\negC4jRPvDlhVjyW594i33p3kXUlef+PqM9YFwDFODO4xxuuOer2qvi/Jy5M8Udfu9Xlfkk9U1QNj\njOdvXv/g4OD68mazyWazufOKAXbQdrvNdrs91bo1ZrirfVV9IckPjDFuufNzVY059sHyqqZPgjDH\nNta4nbXYxXbZxWM6jarKGOPIkYy5zuNu1BwAvc0yA84Y47vn2A4At+fKSYBmzDnJqc0x6fDe3jy1\nwEUmuDm1uSYdBqYR3LBD5vhf0Ve3w3rNcjrgiTtwOiBn4KKeInYRXdTv9UmnA+px05KeJReZHjew\nanrct3I6IEAzghugGWPcwKr5e8atjHEDrJAxboAdIrgBmhHcAM0IboBmBDdAM6sI7tPOs8ad0b5n\nS/ueLe17K8F9AWjfs6V9z5b2vdUqghuA0xPcAM2cy5WTZ7oDgB113JWTZx7cAMzLUAlAM4IboJnF\ng7uqLlfVZ6vqqap659L17JqqerqqPlVVj1fVx5aup7uq+sOqeq6qPn3Da/tV9VhVfa6qHq2qb1+y\nxs6Oad+Dqnr28DP8eFVdXrLGNVg0uKvqriTvTXI5yauSvLmqXrlkTTtoJNmMMe4fYzywdDE74I9y\n7fN6o99I8tgY43uS/MPhc+7MUe07krzn8DN8/xjj7xaoa1WW7nE/kOTzY4ynxxhfTvKBJA8tXNMu\nmuE29CTJGOOfkly96eU3Jnn/4fL7k7zpXIvaIce0b+Iz/DWWDu6XJnnmhufPHr7GfEaSv6+qj1fV\nW5cuZkfdM8Z47nD5uST3LFnMjvrlqnqiqh4xFLV8cDsX8ey9Zoxxf5IfTfJLVfXDSxe0yw6ne/K5\nntcfJHl5klcn+VKS3122nOUtHdxfTHLphueXcq3XzUzGGF86/Pe/knww14anmNdzVXVvklTVdyZ5\nfuF6dsoY4/lxKMn74jO8eHB/PMkrquplVfWSJD+V5EML17Qzquobq+pbDpe/Kcnrk3z65K/iDnwo\nyVsOl9+S5K8WrGXnHP4y/KqfiM/wsrO8jzG+UlVvS/KRJHcleWSM8eSSNe2Ye5J8sK5NkX13kj8Z\nYzy6bEm9VdWfJXkwyXdU1TNJfivJbyf586r6+SRPJ/nJ5Srs7Yj2fTjJpqpenWtDUF9I8gsLlrgK\nLnkHaGbpoRIAXiTBDdCM4AZoRnADNCO4AZoR3ADNCG6AZgQ3QDP/B4Xc1ikAa/yhAAAAAElFTkSu\nQmCC\n", + "image/png": "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\nCBMaRcHF9AAAAABJRU5ErkJggg==\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -160,9 +160,9 @@ }, { "data": { - "image/png": "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\nRK5CYII=\n", + "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -170,9 +170,9 @@ }, { "data": { - "image/png": "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\n0UGDsnsdM9i+PRqju3Z1jPcu2ztTDwC2NGpvBc7J8jWlQIwYAfPnRzPtNEyzlUb/9E9Npw077bTk\napH2GzIEFiyIZqC59VYYMCDRkvIi2+B2sVQRE+f8BKwNDj/c/0UOVdL9OewwuPTS/K0vScOG+Ycc\nnKTHqJk/LNjRZBvcFUDj/+wMwu91N1FSUvLZcmVlBshkudqWff3r8MwzPnDq6uD+++Ff/iUnq8qL\nm2/28xE29Ofb34Z//dekqxKJ3HlndGiprg7uuQd+8IOkqwpTaWkppaWl7XputsG9BBhuZkOAbcBV\nwJTmT2oc3HPmwLp1Wa61FVVV/oTcP/4jPPYYrFmTm/XkS1WVP2F65ZUwd65mAJfCU10NP/0pTJvm\nd5r+8IekKwpXJpMhk8l81p49e3arz80quJ1z+8zsduA3wOHAMyFdUSIiEqKsp811zv038N8x1CIi\nIu3QAS6cERFJFwW3iEhgFNwiIoFRcIuIBEbBLSISGAW3iEhgFNwiIoFRcIuIBEbBLSISGAW3iEhg\nFNwiIoFRcIuIBEbBLSISmKzvDihSaLZvh40b/fJ77yVbSy45B3/8YzS1XMP0XVL4du6EDRv88vr1\nB//zeQnu55+PJjWYNw8a3Ss8p7ZsgVdegc2b43/tF16AtWvhf/8XBg+O//Vb0tCf99/Pz/pCde+9\n8NZb0fyYN9yQbD25smkTjB8PZ5zh26eeCkcdFX1/4UI/9pcsgT598lNTRYUfo9u25Wd9oZo5E954\nA4491renTTu4n89LcNfUwJ49fnnyZPjSl3K/zrFj/cB96CHfjnOdX/sa/O53vk+nnZafeRnHjPGT\nouaiP2mzf7+f/HfK5+ZiSpf9+/0s6S3NOnPDDfDaa36Mjh4NEybkvp7Ro+G556Ix+nd/l/t1hmr/\nfnjwQZg+/dB+Pi/Bfc01+VhLU+ef7//y58KECfn5RWhs/Pjc9UfS56KL/COfzjlHYzRfdHJSRCQw\nCm4RkcAouEVEAqPgFhEJjIJbRCQwCm4RkcAouEVEAqPgFhEJjIJbRCQwCm4RkcDo7oASJOf8Tb4a\n7ozXtSuMGJFsTblSVeVvMNZg8GDo1Su5eqT91q6N7trYpQucdFI8r6vgPoDKSqit9ct1dcnWEofG\n/dm/P9lasrVpk7+RWMMvQlmZv51rvu6Cl0933w2vvgq9e8Pu3f5GbXPnJl1VbqRpjG7d6m+8NXKk\n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\nQmCC\n", + "image/png": "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\neqm80SYAAAAASUVORK5CYII=\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -201,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -231,7 +231,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -267,7 +267,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "collapsed": false }, @@ -281,13 +281,15 @@ " \n", " #prepare the subtemplate of the sequence S_k'\n", " subtemplates = []\n", - " subtemplates.append((init, {})) # append the init pulse first\n", " \n", - " # append the wait pulse next. pass in the appropriate wait time.\n", + " # include the wait pulse first. pass in the appropriate wait time.\n", " # note that the wait time has to be cast to a string. In parameter mappings, some string containing a mathematical\n", " # expression is expected. Here, we provide a mathematical expression consisting only of a constant value.\n", " subtemplates.append((wait, {'wait_duration': str(wait_times[k])}))\n", " \n", + " # append the init pulse\n", + " subtemplates.append((init, {}))\n", + " \n", " # append the k-th sequence\n", " subtemplates.append((sequences[k], all_epsilons_map))\n", " \n", @@ -308,7 +310,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "collapsed": false }, @@ -323,9 +325,9 @@ }, { "data": { - "image/png": "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\nuEVEEub/AVoWuOjZjxMYAAAAAElFTkSuQmCC\n", + "image/png": "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\nf4xOvgU2ya4tAAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -345,7 +347,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 10, "metadata": { "collapsed": false }, @@ -361,6 +363,15 @@ " \n", "scanline = SequencePulseTemplate(subtemplates, all_epsilons)" ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [] } ], "metadata": { From 4df15b6bc035cd47cb82e29c8a91ab9f3152bf03 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 8 Apr 2016 10:46:03 +0200 Subject: [PATCH 20/33] Ignore jupyter-notebook checkpoint files. --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 40ef362cc..3a7c4fdb0 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,5 @@ doc/build/* .eggs* *.egg-info* build/* -dist/* \ No newline at end of file +dist/* +examples/.ipynb_checkpoints/* \ No newline at end of file From 189ab1a5b8588a79a53f67e5ecf6df8d12c664a0 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 14:09:54 +0200 Subject: [PATCH 21/33] Embedded static versions of the jupyter notebook examples into the sphinx documentation. --- .gitignore | 2 +- doc/source/conf.py | 7 +- .../source/examples}/00SimpleTablePulse.ipynb | 40 +- .../source/examples}/01SequencePulse.ipynb | 0 .../source/examples}/02FunctionPulse.ipynb | 0 .../source/examples}/03Serialization.ipynb | 0 .../source/examples}/04Sequencing.ipynb | 0 .../source/examples}/05Parameters.ipynb | 27 +- .../examples}/06ConditionalExecution.ipynb | 0 .../source/examples}/07PulseControl.ipynb | 0 .../source/examples}/08RealWorldCase.ipynb | 4 +- doc/source/examples/examples.rst | 14 +- doc/source/examples/img/example_pulse.png | Bin 0 -> 25364 bytes doc/source/examples/img/example_pulse.svg | 666 ++++++++++++++++++ doc/source/examples/img/gate_pulse_scheme.png | Bin 0 -> 3277 bytes .../examples}/img/gate_pulse_scheme.svg | 0 .../source/examples}/serialized_pulses/main | 0 .../serialized_pulses/sequence_embedded | 0 .../serialized_pulses/sequence_referenced | 0 .../serialized_pulses/stored_template | 0 .../serialized_pulses/table_template | 0 examples/img/example_pulse.svg | 169 ----- 22 files changed, 706 insertions(+), 223 deletions(-) rename {examples => doc/source/examples}/00SimpleTablePulse.ipynb (98%) rename {examples => doc/source/examples}/01SequencePulse.ipynb (100%) rename {examples => doc/source/examples}/02FunctionPulse.ipynb (100%) rename {examples => doc/source/examples}/03Serialization.ipynb (100%) rename {examples => doc/source/examples}/04Sequencing.ipynb (100%) rename {examples => doc/source/examples}/05Parameters.ipynb (93%) rename {examples => doc/source/examples}/06ConditionalExecution.ipynb (100%) rename {examples => doc/source/examples}/07PulseControl.ipynb (100%) rename {examples => doc/source/examples}/08RealWorldCase.ipynb (99%) create mode 100644 doc/source/examples/img/example_pulse.png create mode 100644 doc/source/examples/img/example_pulse.svg create mode 100644 doc/source/examples/img/gate_pulse_scheme.png rename {examples => doc/source/examples}/img/gate_pulse_scheme.svg (100%) rename {examples => doc/source/examples}/serialized_pulses/main (100%) rename {examples => doc/source/examples}/serialized_pulses/sequence_embedded (100%) rename {examples => doc/source/examples}/serialized_pulses/sequence_referenced (100%) rename {examples => doc/source/examples}/serialized_pulses/stored_template (100%) rename {examples => doc/source/examples}/serialized_pulses/table_template (100%) delete mode 100644 examples/img/example_pulse.svg diff --git a/.gitignore b/.gitignore index 3a7c4fdb0..218b5beb7 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,4 @@ doc/build/* *.egg-info* build/* dist/* -examples/.ipynb_checkpoints/* \ No newline at end of file +doc/source/examples/.ipynb_checkpoints/* \ No newline at end of file diff --git a/doc/source/conf.py b/doc/source/conf.py index a37f0b0b6..9a5df27f0 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -39,7 +39,8 @@ 'sphinx.ext.mathjax', 'sphinx.ext.ifconfig', 'sphinx.ext.viewcode', - 'sphinx.ext.autodoc' + 'sphinx.ext.autodoc', + 'nbsphinx' ] # Add any paths that contain templates here, relative to this directory. @@ -85,7 +86,7 @@ # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. -exclude_patterns = [] +exclude_patterns = ['_build', '**.ipynb_checkpoints'] # The reST default role (used for this markup: `text`) to use for all # documents. @@ -149,7 +150,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -html_static_path = ['_static'] +html_static_path = ['_static' 'examples/img'] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied diff --git a/examples/00SimpleTablePulse.ipynb b/doc/source/examples/00SimpleTablePulse.ipynb similarity index 98% rename from examples/00SimpleTablePulse.ipynb rename to doc/source/examples/00SimpleTablePulse.ipynb index 9920ee21e..71c4f18f5 100644 --- a/examples/00SimpleTablePulse.ipynb +++ b/doc/source/examples/00SimpleTablePulse.ipynb @@ -8,7 +8,7 @@ "\n", "This example demonstrates how to set up a simple TablePulseTemplate.\n", "\n", - "\"The\n", + "![The pulse we want to model using the qctoolkit](img/example_pulse.png)\n", "\n", "Assume we want to model a pulse as depicted by the figure above. Since the structure is relatively simple and relies only on a few critical points between which the values are interpolated (indicated by the crosses in the figure), we will do so by using a `TablePulseTemplate` and setting values at appropriate times. First, let us instantiate a `TablePulseTemplate` object:" ] @@ -35,7 +35,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -58,7 +58,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": { "collapsed": false }, @@ -75,7 +75,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -103,7 +103,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": { "collapsed": true }, @@ -124,7 +124,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -133,7 +133,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'tb', 'tend', 'vb', 'ta', 'va'}\n" + "{'va', 'ta', 'tend', 'vb', 'tb'}\n" ] } ], @@ -150,7 +150,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": { "collapsed": false }, @@ -167,7 +167,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -193,7 +193,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": { "collapsed": false }, @@ -210,7 +210,7 @@ "data": { "image/png": "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\nQSHWiZW2AAAAAElFTkSuQmCC\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -226,22 +226,6 @@ " 'tend': 8}\n", "plot(param_template, parameters, sample_rate=100)" ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Yay!" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { @@ -260,7 +244,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/examples/01SequencePulse.ipynb b/doc/source/examples/01SequencePulse.ipynb similarity index 100% rename from examples/01SequencePulse.ipynb rename to doc/source/examples/01SequencePulse.ipynb diff --git a/examples/02FunctionPulse.ipynb b/doc/source/examples/02FunctionPulse.ipynb similarity index 100% rename from examples/02FunctionPulse.ipynb rename to doc/source/examples/02FunctionPulse.ipynb diff --git a/examples/03Serialization.ipynb b/doc/source/examples/03Serialization.ipynb similarity index 100% rename from examples/03Serialization.ipynb rename to doc/source/examples/03Serialization.ipynb diff --git a/examples/04Sequencing.ipynb b/doc/source/examples/04Sequencing.ipynb similarity index 100% rename from examples/04Sequencing.ipynb rename to doc/source/examples/04Sequencing.ipynb diff --git a/examples/05Parameters.ipynb b/doc/source/examples/05Parameters.ipynb similarity index 93% rename from examples/05Parameters.ipynb rename to doc/source/examples/05Parameters.ipynb index 7248b4aeb..9e720db03 100644 --- a/examples/05Parameters.ipynb +++ b/doc/source/examples/05Parameters.ipynb @@ -32,7 +32,7 @@ "data": { "image/png": "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\n", "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -76,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 2, "metadata": { "collapsed": true }, @@ -115,7 +115,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 3, "metadata": { "collapsed": false }, @@ -151,15 +151,13 @@ "source": [ "The `MeasurementManager.is_measurement_available` stub will simply return the value to which we have set the `is_available` member variable of the class.\n", "\n", - "*Attention/Broken: Note that the subtemplates of the `sequence_template` defined above are pushed to the stack manually. Currently, `SequencePulseTemplate` is broken and will require a stop if any of the parameters used by any subtemplate return `True` via `requires_stop()`, resulting in an empty instruction sequence in any case. Needs fixing ([issue 104](https://github.com/qutech/qc-toolkit/issues/104))*\n", - "\n", "When we invoke `Sequencer.build`, for each template on the sequencing stack it first queries whether or not all parameters can be evaluated. If any of them returns `True` via the `requires_stop` method, the sequencing process will be interrupted.\n", "In our example, `Sequencer` will first proceed through the first two subtemplates of `sequence_template`. When it arrives at `dependent_template`, it will stop:" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 4, "metadata": { "collapsed": false }, @@ -168,7 +166,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[, , ]\n" + "[, , ]\n" ] } ], @@ -186,7 +184,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 5, "metadata": { "collapsed": false }, @@ -195,7 +193,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[, , , , ]\n" + "[, , , , ]\n" ] } ], @@ -212,15 +210,6 @@ "We have now obtained the complete sequence with one execution instruction for each `TablePulseTemplate`.\n", "*Attention/Broken: Currently this is incorrect behavior: We would want to only get the remainder of the pulse in the second call since we wouldn't want to execute the first part of the pulse again. Needs fixing ([issue 105](https://github.com/qutech/qc-toolkit/issues/105)).*" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { @@ -239,7 +228,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/examples/06ConditionalExecution.ipynb b/doc/source/examples/06ConditionalExecution.ipynb similarity index 100% rename from examples/06ConditionalExecution.ipynb rename to doc/source/examples/06ConditionalExecution.ipynb diff --git a/examples/07PulseControl.ipynb b/doc/source/examples/07PulseControl.ipynb similarity index 100% rename from examples/07PulseControl.ipynb rename to doc/source/examples/07PulseControl.ipynb diff --git a/examples/08RealWorldCase.ipynb b/doc/source/examples/08RealWorldCase.ipynb similarity index 99% rename from examples/08RealWorldCase.ipynb rename to doc/source/examples/08RealWorldCase.ipynb index f4b80f54f..d63b049f4 100644 --- a/examples/08RealWorldCase.ipynb +++ b/doc/source/examples/08RealWorldCase.ipynb @@ -20,7 +20,7 @@ "\n", "The template for a gate pulse $G_j$ is a sequence of $\\epsilon_i, 0 \\leq i \\lt N_{G_j}$ voltage levels held for time $\\Delta t = 1$ ns as illustrated in the figure below (with $N_{G_j} = 7$).\n", "\n", - "\"Template\n", + "![Template of a gate pulse](img/gate_pulse_scheme.png)\n", "\n", "The experiment defines a number of sequences $S_k, 0 \\leq k \\lt N_{Sequences}$ of the $G_j$ as $$S_k = (G_{m_k(1)}, G_{m_k(2)}, \\dots, G_{m_k(N_{S_k})})$$ where $N_{S_k}$ is the length of sequence $k$ and $m_k(i): \\{0, \\dots, N_{S_k} - 1\\} \\rightarrow \\{0, \\dots, N_{Gates} - 1\\}$ is a function that maps an index $i$ to the $m_k(i)$-th gate of sequence $S_k$ and thus fully describes the sequence. (These sequences express the sequential application of the gates to the qubit. In terms of quantum mathematics they may rather be expressed as multiplication of the matrices describing the unitary transformations applied by the gates: $S_k = \\prod_{i=N_{S_k} - 1}^{0} G_{m_k(i)} = G_{(N_{S_k} - 1)} \\cdot \\dots \\cdot G_{1} \\cdot G_{0}$.)\n", "\n", @@ -390,7 +390,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/doc/source/examples/examples.rst b/doc/source/examples/examples.rst index 029dbbbc4..cd40398e7 100644 --- a/doc/source/examples/examples.rst +++ b/doc/source/examples/examples.rst @@ -1,5 +1,17 @@ +.. _examples: + Examples ======== +All examples are provided as static text in this documentation and, additionally, as interactive jupyter notebooks accessible by running `jupyter notebook` in the `/doc/source/examples` directory of the source tree. + .. toctree:: - TablePulseTemplate_example \ No newline at end of file + 00SimpleTablePulse + 01SequencePulse + 02FunctionPulse + 03Serialization + 04Sequencing + 05Parameters + 06ConditionalExecution + 07PulseControl + 08RealWorldCase \ No newline at end of file diff --git a/doc/source/examples/img/example_pulse.png b/doc/source/examples/img/example_pulse.png new file mode 100644 index 0000000000000000000000000000000000000000..17f90eb00fe28da7732784da7d93d8fa6af13598 GIT binary patch literal 25364 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 I1Gl^X12vG$`~Uy| literal 0 HcmV?d00001 diff --git a/doc/source/examples/img/example_pulse.svg b/doc/source/examples/img/example_pulse.svg new file mode 100644 index 000000000..84cbfec72 --- /dev/null +++ b/doc/source/examples/img/example_pulse.svg @@ -0,0 +1,666 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + V + + b + + V + + a + + 0 + + 0 + + t + + b + + t + + a + + t + + end + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Linear interpolation + + + + + + + + + + + Hold interpolation + + + + + + + + + + + “Inverse hold” interpolation + + + + + + Supporting point + + Pulse voltage + + + + + + + + + + + + + + + + + + + +length + + + + + + + + + + +start + + \ No newline at end of file diff --git a/doc/source/examples/img/gate_pulse_scheme.png b/doc/source/examples/img/gate_pulse_scheme.png new file mode 100644 index 0000000000000000000000000000000000000000..dc3b89a46d3097652a044679ddc6877b815f0dfb GIT binary patch literal 3277 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 LNkvXXu0mjf*54?9 literal 0 HcmV?d00001 diff --git a/examples/img/gate_pulse_scheme.svg b/doc/source/examples/img/gate_pulse_scheme.svg similarity index 100% rename from examples/img/gate_pulse_scheme.svg rename to doc/source/examples/img/gate_pulse_scheme.svg diff --git a/examples/serialized_pulses/main b/doc/source/examples/serialized_pulses/main similarity index 100% rename from examples/serialized_pulses/main rename to doc/source/examples/serialized_pulses/main diff --git a/examples/serialized_pulses/sequence_embedded b/doc/source/examples/serialized_pulses/sequence_embedded similarity index 100% rename from examples/serialized_pulses/sequence_embedded rename to doc/source/examples/serialized_pulses/sequence_embedded diff --git a/examples/serialized_pulses/sequence_referenced b/doc/source/examples/serialized_pulses/sequence_referenced similarity index 100% rename from examples/serialized_pulses/sequence_referenced rename to doc/source/examples/serialized_pulses/sequence_referenced diff --git a/examples/serialized_pulses/stored_template b/doc/source/examples/serialized_pulses/stored_template similarity index 100% rename from examples/serialized_pulses/stored_template rename to doc/source/examples/serialized_pulses/stored_template diff --git a/examples/serialized_pulses/table_template b/doc/source/examples/serialized_pulses/table_template similarity index 100% rename from examples/serialized_pulses/table_template rename to doc/source/examples/serialized_pulses/table_template diff --git a/examples/img/example_pulse.svg b/examples/img/example_pulse.svg deleted file mode 100644 index 58591ab16..000000000 --- a/examples/img/example_pulse.svg +++ /dev/null @@ -1,169 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - V - b - V - a - 0 - 0 - t - b - t - a - t - end - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Linear interpolation - - - - - - - - - - Hold interpolation - - - - - - - - - - “Inverse hold” interpolation - - - - - Supporting point - Pulse voltage - - - - - - - - - - - - - - - - - - -length - - - - - - - - - -start - From 7a95fb4a2f3bef9259cd12b1c2eebc2d75602eff Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 14:50:41 +0200 Subject: [PATCH 22/33] Added sphinx and nbsphinx as extra requirements for documentation. --- requirements.readthedocs.txt | 2 ++ requirements.txt | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 requirements.readthedocs.txt create mode 100644 requirements.txt diff --git a/requirements.readthedocs.txt b/requirements.readthedocs.txt new file mode 100644 index 000000000..0b7e3f611 --- /dev/null +++ b/requirements.readthedocs.txt @@ -0,0 +1,2 @@ +nbsphinx +ipykernel \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 000000000..0b7e3f611 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +nbsphinx +ipykernel \ No newline at end of file From 18c29b15b0112050d4bfdf5faa9fd164ef4e07ca Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 15:22:18 +0200 Subject: [PATCH 23/33] Added numpy as requirement in setup.py. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2c3ec9e43..f68dd84b6 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ package_dir = {'qctoolkit': 'qctoolkit'}, packages=packages, tests_require=['pytest'], - install_requires= ['py_expression_eval'] + requires_typing, + install_requires= ['py_expression_eval', 'numpy'] + requires_typing, extras_require={ 'testing' : ['pytest'], 'plotting' : ['matplotlib'], From ab3c8385603fc2c183f599a9f577f180050c42d8 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 15:15:08 +0200 Subject: [PATCH 24/33] Added readthedocs.yml. --- readthedocs.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 readthedocs.yml diff --git a/readthedocs.yml b/readthedocs.yml new file mode 100644 index 000000000..1806da8be --- /dev/null +++ b/readthedocs.yml @@ -0,0 +1,3 @@ +python: + setup_py_install: true + version: 3 \ No newline at end of file From 890088a6bdc11e57e5a33621c9b5e0020e002f79 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 15:45:20 +0200 Subject: [PATCH 25/33] Some cleanup of readthedocs related configuration. --- requirements.txt => doc/requirements.txt | 0 readthedocs.yml | 1 + requirements.readthedocs.txt | 2 -- 3 files changed, 1 insertion(+), 2 deletions(-) rename requirements.txt => doc/requirements.txt (100%) delete mode 100644 requirements.readthedocs.txt diff --git a/requirements.txt b/doc/requirements.txt similarity index 100% rename from requirements.txt rename to doc/requirements.txt diff --git a/readthedocs.yml b/readthedocs.yml index 1806da8be..361e102a0 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -1,3 +1,4 @@ +requirements_file: doc/requirements.txt python: setup_py_install: true version: 3 \ No newline at end of file diff --git a/requirements.readthedocs.txt b/requirements.readthedocs.txt deleted file mode 100644 index 0b7e3f611..000000000 --- a/requirements.readthedocs.txt +++ /dev/null @@ -1,2 +0,0 @@ -nbsphinx -ipykernel \ No newline at end of file From cf3f34e62749e02a2b951d65313c8674282d960e Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 16:22:42 +0200 Subject: [PATCH 26/33] Readme.md file for doc folder. --- doc/README.md | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 doc/README.md diff --git a/doc/README.md b/doc/README.md new file mode 100644 index 000000000..708df9f62 --- /dev/null +++ b/doc/README.md @@ -0,0 +1,14 @@ +# qc-toolkit: Quantum Computing Toolkit - Documentation + +This folder contains texts, configuration and scripts which are used to compile the documentation using [sphinx](http://www.sphinx-doc.org/en/stable/). It also contains usage examples for the qctoolkit. +You may either build the documentation yourself or read it on [readthedocs](http://qc-toolkit.readthedocs.org/).[![Documentation Status](https://readthedocs.org/projects/qc-toolkit/badge/?version=latest)](http://qc-toolkit.readthedocs.org/en/latest/?badge=latest) + + +## Examples +In the subdirectory *examples* you can find various [Jupyter notebook](http://jupyter.org/) files providing some step-by-step examples of how the qctoolkit can be used. These can be explored in an interactive fashion by running the *Jupyter notebook* application inside the folder. However, a static version will also be included in the documentation created with *sphinx*. + +## Building the Documentation +To build the documentation, you will need [sphinx](http://www.sphinx-doc.org/en/stable/) and [nbsphinx](https://nbsphinx.readthedocs.org/) which, in turn, requires [pandoc](http://pandoc.org/). If the last two are not present, the examples won't be included in the documentation. +Users of Anaconda on MS Windows may install these by executing `pip install sphinx nbsphinx` and `conda install -c https://conda.binstar.org/asmeurer pandoc`. + +The documentation is built by invoking `make ` inside the */doc* directory, where `` is an output format supported by *sphinx*, e.g., `html`. The output will then be found in `/doc/build/`. \ No newline at end of file From 464605cc9f11f44d57d2728912f244d177cf3d51 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 15 Apr 2016 17:26:10 +0200 Subject: [PATCH 27/33] Documentation: Referenced example in concept text about serialization. --- doc/source/concepts/serialization.rst | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/source/concepts/serialization.rst b/doc/source/concepts/serialization.rst index 85ba685ae..0e47b9ac9 100644 --- a/doc/source/concepts/serialization.rst +++ b/doc/source/concepts/serialization.rst @@ -10,9 +10,7 @@ The implementation of (de)serialization features :class:`.Serializer` class and The essential methods of :class:`.Serializer` are :meth:`.Serializer.serialize` and :meth:`.Serializer.deserialize`. :meth:`.Serializer.serialize` serializes a serializable object (i.e., any object of a class that implements/derives from :class:`.Serializable`) in a recursive process: It invokes the :meth:`.Serializable.get_serialization_data` method of the provided serializable object, which in turn might invoke the :class:`.Sequencer` to obtain a serialization for complex embedded data (such as a :class:`.ParameterDeclaration` in a :class:`.TablePulseTemplate`). In the end, a dictionary representation of the object is obtained which is then converted into a JSON string using built-in Python functionality. The JSON representation is finally stored using a given :class:`.StorageBackend`. Deserialization (:meth:`.Serializer.deserialize`) works analogously and is thus not explained in detail here. -For an example of how to use serialization to store and load pulse templates, see . - -.. note:: write examples +For an example of how to use serialization to store and load pulse templates, see :ref:`examples/03Serialization.ipynb` in the examples section. Implementing a :class:`.Serializable` Class ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ From 394673a8f77d138ed0c5e8c8821b88e50e71ccbd Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 29 Apr 2016 10:23:41 +0200 Subject: [PATCH 28/33] Some slight changes in wording/formulations in concept documentation files. Added author for sphinx documentation. --- doc/source/concepts/branching.rst | 8 ++++---- doc/source/concepts/pulsetemplates.rst | 5 +++++ doc/source/concepts/sequencing.rst | 2 +- doc/source/conf.py | 4 ++-- 4 files changed, 12 insertions(+), 7 deletions(-) diff --git a/doc/source/concepts/branching.rst b/doc/source/concepts/branching.rst index ef79dd8a0..d5e50e500 100644 --- a/doc/source/concepts/branching.rst +++ b/doc/source/concepts/branching.rst @@ -3,16 +3,16 @@ Conditional Branching --------------------- -The qctoolkit was designed to model conditional branching in pulse execution using the classes :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` of the :ref:`pulse template definition classes `. The software is intended to support use of trigger-based hardware jumps between waveforms as well as software-based evaluation of branching conditions, if the hardware does not support triggers or highly sophisticated evaluation of measured data is required. These options are represented as instances of the :class:`.Condition` class: :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` both contain unique identifiers (chosen by the user) of a condition. In the beginning of the :ref:`sequencing process `, the user provides a dictionary of :class:`.Condition` instances which are used to determine how the conditions for each template are evaluated. Currently, two different subclasses of :class:`.Condition` exist: :class:`.SoftwareCondition` represents a software-evaluated condition and accepts a function reference to any evaluation function (which must return None, if it cannot yet be evaluated, or a boolean value); :class:`.HardwareCondition` represents trigger-based hardware evaluation and basically stores a reference to a trigger which will later be evaluated by the specific hardware driver to set up the device accordingly. Note that software-based evaluation will interrupt the sequencing process and thus the execution of the pulse, if the evaluation cannot be performed during the sequencing run, e.g., if the evaluation of the condition is based on measurement data made during pulse execution. In this case, the pulse instruction sequence is only generated up to the branching and must be re-invoked later on, after executing this first part and obtaining the required data. Software-based evaluation is thus not applicable when high performance is required. +The qctoolkit was designed to model conditional branching in pulse execution using the classes :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` of the :ref:`pulse template definition classes `. The software is intended to support use of trigger-based hardware jumps between waveforms as well as software-based evaluation of branching conditions, if the hardware does not support triggers or highly sophisticated evaluation of measured data is required. These options are represented as instances of the :class:`.Condition` class: :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` both contain unique identifiers (chosen by the user) of a condition. In the beginning of the :ref:`sequencing process `, the user provides a dictionary of :class:`.Condition` instances which are used to determine how the conditions for each template are evaluated. Currently, two different subclasses of :class:`.Condition` exist: :class:`.SoftwareCondition` represents a software-evaluated condition and accepts a function reference to any evaluation function which must return a boolean value indicating whether or not the condition is fulfilled or None, if it cannot yet be evaluated; :class:`.HardwareCondition` represents trigger-based hardware evaluation and basically stores a reference to a trigger which will later be evaluated by the specific hardware driver to set up the device accordingly. Note that software-based evaluation will interrupt the sequencing process and thus the execution of the pulse if the evaluation cannot be performed during the sequencing run, e.g., if the evaluation of the condition is based on measurement data made during pulse execution. In this case, the pulse instruction sequence is only generated up to the branching and must be re-invoked later on, after executing this first part and obtaining the required data. Software-based evaluation is thus not feasible when high performance is required. Sequencing of Conditional Branching ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware never knows of the other path). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the caveat of being not real-time capable (as explained above). +Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware will then never know of potential other execution paths). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the disadvantage of being not real-time capable (as explained above). -A note on implementation: The abstract :class:`.Condition` class defines an methods for generating sequences for branches or loops and to query if the condition can be evaluated. These are implemented by :class:`.SoftwareCondition` and :class:`.HardwareCondition` in the ways mentioned above. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` make use of the respective methods in their :meth:`.SequencingElement.build_sequence` method to defer sequence construction to the condition. Thus, during the sequencing process, the :class:`.Sequencer` calls :meth:`.SequencingElement.build_sequence` on the template which in turn invokes :meth:`.Condition.build_sequence_branch` or :meth:`.Condition.build_sequence_loop`. These then perform the actual sequence generation. These indirections allow for each class to act independently of the exact combination of if-else-branching versus looping and software- or hardware-based evaluation. +A note on implementation: The abstract :class:`.Condition` class defines methods for generating sequences for branches or loops and to query if the condition can be evaluated. These are implemented by :class:`.SoftwareCondition` and :class:`.HardwareCondition` in the ways mentioned above. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` make use of the respective methods in their :meth:`.SequencingElement.build_sequence` method to defer sequence construction to the condition. Thus, during the sequencing process, the :class:`.Sequencer` calls :meth:`.SequencingElement.build_sequence` on the template which in turn invokes :meth:`.Condition.build_sequence_branch` or :meth:`.Condition.build_sequence_loop`. These then perform the actual sequence generation. These indirections allow for each class to act independently of the exact combination of if-else-branching versus looping and software- or hardware-based evaluation. Future Work ^^^^^^^^^^^ Currently, there is no detailed concept on hardware abstraction and thus no meaningful representation of triggers and no hardware driver implementation that configures any device. This is still an open task. -It is quite common for hardware to allow triggers to be not only a boolean signal but, e.g., any 8-bit signal, thus enabling more than two branches. While this should still be covered by the current classes by nesting :class:`.BranchPulseTemplate`s and configuring triggers appropriately, the implementation of a template class which acts like a C-style switch statement might be a worthwhile consideration. \ No newline at end of file +It is quite common for hardware to allow triggers that are represented not only a boolean signal but, e.g., any 8-bit signal, thus enabling more than two branching options. While this could still be represented by the current classes by nesting :class:`.BranchPulseTemplate` objects and configuring triggers appropriately, the implementation of a template class which acts like a C-style switch statement might be a worthwhile consideration. \ No newline at end of file diff --git a/doc/source/concepts/pulsetemplates.rst b/doc/source/concepts/pulsetemplates.rst index 05a9084cf..2204543be 100644 --- a/doc/source/concepts/pulsetemplates.rst +++ b/doc/source/concepts/pulsetemplates.rst @@ -21,6 +21,11 @@ Obtaining a Concrete Pulse To obtain a pulse ready for execution on the hardware from a pulse template, the user has to specify parameter values (if parameters were used in the pulse templates in question). In the simplest case, parameters are constant values that can be provided as plain float values. Other cases may require parameter values to be computed based on some measurement values obtained during preceding executions. If so, a subclass of the :class:`.Parameter` class which performs this computations when queried for a value can be provided. In order to translate the object structures that encode the pulse template in the software into a sequential representation of the concrete pulse with the given parameter values that is understandable by the hardware, the sequencing process has to be invoked. During this process, all parameter values are checked for consistency with the boundaries declared by the parameter declarations and the process is aborted if any violation occurs. :ref:`Read more about the sequencing process `. +Relevant Examples +^^^^^^^^ + +Examples demonstrating the use of pulse templates and parameters are :ref:`examples/00SimpleTablePulse.ipynb`, :ref:`examples/01SequencePulse.ipynb` and :ref:`examples/02FunctionPulse.ipynb`. + .. rubric:: Footnotes .. [#tree] Regarded as objects in the programming language, each pulse template is a tree of PulseTemplate objects, where the atomic templates (:class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects) are the leafs while the remaining ones form the inner nodes of the tree. .. [#pattern] The design of the pulse template class hierarchy is an application of the `Composite Pattern `_. diff --git a/doc/source/concepts/sequencing.rst b/doc/source/concepts/sequencing.rst index 6eabea92d..f6c80e46a 100644 --- a/doc/source/concepts/sequencing.rst +++ b/doc/source/concepts/sequencing.rst @@ -9,7 +9,7 @@ This approach was inspired by translation of syntax trees to machine instruction The sequencing process is performed by a :class:`.Sequencer` and started with a call to :meth:`.Sequencer.build`. :class:`.Sequencer` maintains a stack of :class:`.SequencingElement` objects (i.e. pulse templates) that still need to be translated. Pushing a pulse template to the stack using :meth:`.Sequencer.push` will cause :class:`.Sequencer` to translate it next. Translation works as follows: :class:`.Sequencer` pops the first element from the stack and calls its :meth:`.SequencingElement.build_sequence` method. In the case of a :class:`.TablePulseTemplate`, this adds an :class:`.EXECInstruction` referring to a :class:`.TableWaveform` to the instruction sequence. In the case of a :class:`.SequencePulseTemplate`, this simply adds all subtemplates to the sequencing stack such that they are translated next. :class:`.FunctionPulseTemplate` and :class:`.RepetitionPulseTemplate` act very similarly. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` behave in a more complicated way due to their branching ability. :ref:`Read more on conditional branching `. -The sequencing process can be interrupted at any point, e.g., if some parameter value depends on measurements that are to be made in the preceding part of the pulse. In this case, the method :meth:`.SequencingElement.requires_stop` of the first stack element will return `true`. :class:`.Sequencer` then stops the translation and returns the instruction sequence generated so far. This can then be executed and measurement can be made. Afterwards, the sequencing process can be invoked again. :class:`.Sequencer` will resume where it was interrupted previously (with the first item that remained on the stack). :meth:`.Sequencer.has_finished` allows to check, whether the sequencing process was completed. +The sequencing process can be interrupted at any point, e.g., if some parameter value depends on measurements that are to be made in the preceding part of the pulse. In this case, the method :meth:`.SequencingElement.requires_stop` of the first stack element will return `true`. :class:`.Sequencer` then stops the translation and returns the instruction sequence generated so far. This can then be executed and measurements can be made. Afterwards, the sequencing process can be invoked again. :class:`.Sequencer` will resume where it was interrupted previously (with the first item that remained on the stack). :meth:`.Sequencer.has_finished` allows to check, whether the sequencing process was completed. Sequencing Process Example ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/conf.py b/doc/source/conf.py index 9a5df27f0..eb9d62ca4 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -59,8 +59,8 @@ # General information about the project. project = 'qc-toolkit' -copyright = '2015, TODO: Author' -author = 'TODO: Author' +copyright = '2015-2016, Quantum Technology Group, RWTH Aachen University' +author = 'Quantum Technology Group, RWTH Aachen University' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the From f782bc373fb3fad627bcb7e4616cbd5c9a9eeeb9 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 29 Apr 2016 17:23:44 +0200 Subject: [PATCH 29/33] Rudimentary implementation of BranchPulseTemplate (used in examples for illustration purposes). --- qctoolkit/pulses/branch_pulse_template.py | 49 ++++++++++++++++++----- qctoolkit/pulses/conditions.py | 12 +++++- qctoolkit/pulses/loop_pulse_template.py | 14 +------ 3 files changed, 53 insertions(+), 22 deletions(-) diff --git a/qctoolkit/pulses/branch_pulse_template.py b/qctoolkit/pulses/branch_pulse_template.py index 29fa1effa..b81577024 100644 --- a/qctoolkit/pulses/branch_pulse_template.py +++ b/qctoolkit/pulses/branch_pulse_template.py @@ -1,16 +1,19 @@ import logging -from typing import Dict, Set, List +from typing import Dict, Set, List, Optional, Any """RELATED THIRD PARTY IMPORTS""" """LOCAL IMPORTS""" -from .parameters import Parameter -from .pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.parameters import Parameter +from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow +from qctoolkit.pulses.conditions import Condition, ConditionMissingException +from qctoolkit.pulses.sequencing import Sequencer, InstructionBlock __all__ = ["BranchPulseTemplate"] logger = logging.getLogger(__name__) + class BranchPulseTemplate(PulseTemplate): """Conditional branching in a pulse. @@ -26,14 +29,14 @@ class BranchPulseTemplate(PulseTemplate): Both branches must be of the same length. """ - def __init__(self) -> None: - super().__init__() - self.else_branch = None - self.if_branch = None - raise NotImplementedError() + def __init__(self, condition: str, if_branch: PulseTemplate, else_branch: PulseTemplate, identifier: Optional[str]=None) -> None: + super().__init__(identifier=identifier) + self.__condition = condition + self.__if_branch = if_branch + self.__else_branch = else_branch def __str__(self) -> str: - raise NotImplementedError() + return "BranchPulseTemplate: Condition <{}>, If-Branch <{}>, Else-Branch <{}>".format(self.__condition, self.__if_branch, self.__else_branch) @property def parameter_names(self) -> Set[str]: @@ -54,4 +57,32 @@ def is_interruptable(self) -> bool: """Return True, if this PulseTemplate contains points at which it can halt if interrupted.""" raise NotImplementedError() + def __obtain_condition_object(self, conditions: Dict[str, Condition]) -> Condition: + try: + return conditions[self.__condition] + except: + ConditionMissingException(self.__condition) + + def build_sequence(self, + sequencer: Sequencer, + parameters: Dict[str, Parameter], + conditions: Dict[str, Condition], + instruction_block: InstructionBlock) -> None: + self.__obtain_condition_object(conditions).build_sequence_branch(self, + self.__if_branch, + self.__else_branch, + sequencer, + parameters, + conditions, + instruction_block) + + def requires_stop(self, parameters: Dict[str, Parameter], conditions: Dict[str, Condition]) -> bool: + return self.__obtain_condition_object(conditions).requires_stop() + + def get_serialization_data(self, serializer: 'Serializer') -> Dict[str, Any]: + raise NotImplementedError() + + @staticmethod + def deserialize(serializer: 'Serializer', **kwargs) -> 'BranchPulseTemplate': + raise NotImplementedError() diff --git a/qctoolkit/pulses/conditions.py b/qctoolkit/pulses/conditions.py index fa19c5f2a..c3c761bbd 100644 --- a/qctoolkit/pulses/conditions.py +++ b/qctoolkit/pulses/conditions.py @@ -187,4 +187,14 @@ class ConditionEvaluationException(Exception): """Indicates that a SoftwareCondition cannot be evaluated yet.""" def __str__(self) -> str: - return "The Condition can currently not be evaluated." \ No newline at end of file + return "The Condition can currently not be evaluated." + + +class ConditionMissingException(Exception): + + def __init__(self, condition_name: str) -> None: + super().__init__() + self.condition_name = condition_name + + def __str__(self) -> str: + return "Condition <{}> was referred to but not provided in the conditions dictionary.".format(self.condition_name) \ No newline at end of file diff --git a/qctoolkit/pulses/loop_pulse_template.py b/qctoolkit/pulses/loop_pulse_template.py index 3b7cf96a5..fad9561b9 100644 --- a/qctoolkit/pulses/loop_pulse_template.py +++ b/qctoolkit/pulses/loop_pulse_template.py @@ -7,7 +7,7 @@ from qctoolkit.pulses.parameters import Parameter from qctoolkit.pulses.pulse_template import PulseTemplate, MeasurementWindow -from qctoolkit.pulses.conditions import Condition +from qctoolkit.pulses.conditions import Condition, ConditionMissingException from qctoolkit.pulses.instructions import InstructionBlock from qctoolkit.pulses.sequencing import Sequencer @@ -87,14 +87,4 @@ def deserialize(serializer: Serializer, body: Dict[str, Any], identifier: Optional[str]=None) -> 'LoopPulseTemplate': body = serializer.deserialize(body) - return LoopPulseTemplate(condition, body, identifier=identifier) - - -class ConditionMissingException(Exception): - - def __init__(self, condition_name: str) -> None: - super().__init__() - self.condition_name = condition_name - - def __str__(self) -> str: - return "Condition <{}> was referred to but not provided in the conditions dictionary.".format(self.condition_name) \ No newline at end of file + return LoopPulseTemplate(condition, body, identifier=identifier) \ No newline at end of file From ff5ed6db62a8dcf8026b72b25277b5f900d257cc Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 29 Apr 2016 17:24:19 +0200 Subject: [PATCH 30/33] In-Depth documentation of the sequencing process. --- doc/source/concepts/branching.rst | 6 - doc/source/concepts/concepts.rst | 4 +- doc/source/concepts/sequencing.rst | 26 +- .../examples/06ConditionalExecution.ipynb | 4 +- .../09DetailedSequencingWalkthrough.ipynb | 853 +++++++ doc/source/examples/examples.rst | 3 +- .../examples/img/sequencing_walkthrough.svg | 2207 +++++++++++++++++ doc/source/examples/img/walkthrough1_01.png | Bin 0 -> 24567 bytes doc/source/examples/img/walkthrough1_02.png | Bin 0 -> 38015 bytes doc/source/examples/img/walkthrough2_01.png | Bin 0 -> 32840 bytes doc/source/examples/img/walkthrough2_02.png | Bin 0 -> 39272 bytes doc/source/examples/img/walkthrough2_03.png | Bin 0 -> 71502 bytes doc/source/examples/img/walkthrough2_04.png | Bin 0 -> 69408 bytes doc/source/examples/img/walkthrough2_05.png | Bin 0 -> 38697 bytes 14 files changed, 3089 insertions(+), 14 deletions(-) create mode 100644 doc/source/examples/09DetailedSequencingWalkthrough.ipynb create mode 100644 doc/source/examples/img/sequencing_walkthrough.svg create mode 100644 doc/source/examples/img/walkthrough1_01.png create mode 100644 doc/source/examples/img/walkthrough1_02.png create mode 100644 doc/source/examples/img/walkthrough2_01.png create mode 100644 doc/source/examples/img/walkthrough2_02.png create mode 100644 doc/source/examples/img/walkthrough2_03.png create mode 100644 doc/source/examples/img/walkthrough2_04.png create mode 100644 doc/source/examples/img/walkthrough2_05.png diff --git a/doc/source/concepts/branching.rst b/doc/source/concepts/branching.rst index d5e50e500..5def89543 100644 --- a/doc/source/concepts/branching.rst +++ b/doc/source/concepts/branching.rst @@ -5,12 +5,6 @@ Conditional Branching The qctoolkit was designed to model conditional branching in pulse execution using the classes :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` of the :ref:`pulse template definition classes `. The software is intended to support use of trigger-based hardware jumps between waveforms as well as software-based evaluation of branching conditions, if the hardware does not support triggers or highly sophisticated evaluation of measured data is required. These options are represented as instances of the :class:`.Condition` class: :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` both contain unique identifiers (chosen by the user) of a condition. In the beginning of the :ref:`sequencing process `, the user provides a dictionary of :class:`.Condition` instances which are used to determine how the conditions for each template are evaluated. Currently, two different subclasses of :class:`.Condition` exist: :class:`.SoftwareCondition` represents a software-evaluated condition and accepts a function reference to any evaluation function which must return a boolean value indicating whether or not the condition is fulfilled or None, if it cannot yet be evaluated; :class:`.HardwareCondition` represents trigger-based hardware evaluation and basically stores a reference to a trigger which will later be evaluated by the specific hardware driver to set up the device accordingly. Note that software-based evaluation will interrupt the sequencing process and thus the execution of the pulse if the evaluation cannot be performed during the sequencing run, e.g., if the evaluation of the condition is based on measurement data made during pulse execution. In this case, the pulse instruction sequence is only generated up to the branching and must be re-invoked later on, after executing this first part and obtaining the required data. Software-based evaluation is thus not feasible when high performance is required. -Sequencing of Conditional Branching -^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware will then never know of potential other execution paths). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the disadvantage of being not real-time capable (as explained above). - -A note on implementation: The abstract :class:`.Condition` class defines methods for generating sequences for branches or loops and to query if the condition can be evaluated. These are implemented by :class:`.SoftwareCondition` and :class:`.HardwareCondition` in the ways mentioned above. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` make use of the respective methods in their :meth:`.SequencingElement.build_sequence` method to defer sequence construction to the condition. Thus, during the sequencing process, the :class:`.Sequencer` calls :meth:`.SequencingElement.build_sequence` on the template which in turn invokes :meth:`.Condition.build_sequence_branch` or :meth:`.Condition.build_sequence_loop`. These then perform the actual sequence generation. These indirections allow for each class to act independently of the exact combination of if-else-branching versus looping and software- or hardware-based evaluation. - Future Work ^^^^^^^^^^^ Currently, there is no detailed concept on hardware abstraction and thus no meaningful representation of triggers and no hardware driver implementation that configures any device. This is still an open task. diff --git a/doc/source/concepts/concepts.rst b/doc/source/concepts/concepts.rst index 18ae3671b..1fb0bd641 100644 --- a/doc/source/concepts/concepts.rst +++ b/doc/source/concepts/concepts.rst @@ -6,5 +6,5 @@ This section will explain the fundamental design concepts of the qctoolkit. .. toctree:: pulsetemplates serialization - sequencing - branching \ No newline at end of file + branching + sequencing \ No newline at end of file diff --git a/doc/source/concepts/sequencing.rst b/doc/source/concepts/sequencing.rst index f6c80e46a..51670312b 100644 --- a/doc/source/concepts/sequencing.rst +++ b/doc/source/concepts/sequencing.rst @@ -3,15 +3,35 @@ Sequencing ---------- +Overview and Usage +^^^^^^^^^^^^^^^^^^ + Defining pulses using the :ref:`pulse template definition class structures ` yields a tree structure of :class:`.PulseTemplate` objects. To obtain a concrete pulse that can be executed, parameters have to be replaced by corresponding values and the object structure has to be converted into a sequence of waveforms (and possibly triggered jump annotations) that the hardware drivers can comprehend. This process is called *sequencing* in the qctoolkit. It converts :class:`.TablePulseTemplate` and :class:`.FunctionPulseTemplate` objects into a waveform representation by sampling voltage values along the time domain using the specified interpolation rules between table values or evaluating the defining function respectively. The tree structure arising from the use of :class:`.SequencePulseTemplate`, :class:`.RepetitionPulseTemplate`, :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` is converted into an intermediate instruction language consisting of four instructions: Execute a waveform (:class:`.EXECInstruction`), an unconditional goto to another instruction (:class:`.GOTOInstruction`), a conditional jump to another instruction (:class:`.JMPInstruction`) and a stop command, halting execution (:class:`.STOPInstruction`). This approach was inspired by translation of syntax trees to machine instructions in modern compilers and necessitated by the fact that the hardware requires sequential commands rather than convoluted object structures. The output of the sequencing process is a set of waveforms and a sequence of instructions. These will later be interpreted by hardware drivers which will configure the specific devices accordingly (assuming these are capable of the required functionality). If :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` are not used, the compiled instruction sequence will consist only of execution instructions followed by a stop instruction, which represents a simple sequence of waveforms to play back. -The sequencing process is performed by a :class:`.Sequencer` and started with a call to :meth:`.Sequencer.build`. :class:`.Sequencer` maintains a stack of :class:`.SequencingElement` objects (i.e. pulse templates) that still need to be translated. Pushing a pulse template to the stack using :meth:`.Sequencer.push` will cause :class:`.Sequencer` to translate it next. Translation works as follows: :class:`.Sequencer` pops the first element from the stack and calls its :meth:`.SequencingElement.build_sequence` method. In the case of a :class:`.TablePulseTemplate`, this adds an :class:`.EXECInstruction` referring to a :class:`.TableWaveform` to the instruction sequence. In the case of a :class:`.SequencePulseTemplate`, this simply adds all subtemplates to the sequencing stack such that they are translated next. :class:`.FunctionPulseTemplate` and :class:`.RepetitionPulseTemplate` act very similarly. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` behave in a more complicated way due to their branching ability. :ref:`Read more on conditional branching `. +The sequencing process is performed by a :class:`.Sequencer` and started with a call to :meth:`.Sequencer.build`. :class:`.Sequencer` maintains a stack of :class:`.SequencingElement` objects (i.e. pulse templates) that still need to be translated. Pushing a pulse template to the stack using :meth:`.Sequencer.push` will cause :class:`.Sequencer` to translate it next. Translation works as follows: :class:`.Sequencer` pops the first element from the stack and calls its :meth:`.SequencingElement.build_sequence` method. In the case of a :class:`.TablePulseTemplate`, this adds an :class:`.EXECInstruction` referring to a :class:`.TableWaveform` to the instruction sequence. In the case of a :class:`.SequencePulseTemplate`, this simply adds all subtemplates to the sequencing stack such that they are translated next. :class:`.FunctionPulseTemplate` and :class:`.RepetitionPulseTemplate` act very similarly. :class:`.BranchPulseTemplate` and :class:`.LoopPulseTemplate` behave in a more complicated way due to their branching ability. See the section on implementation details below. The sequencing process can be interrupted at any point, e.g., if some parameter value depends on measurements that are to be made in the preceding part of the pulse. In this case, the method :meth:`.SequencingElement.requires_stop` of the first stack element will return `true`. :class:`.Sequencer` then stops the translation and returns the instruction sequence generated so far. This can then be executed and measurements can be made. Afterwards, the sequencing process can be invoked again. :class:`.Sequencer` will resume where it was interrupted previously (with the first item that remained on the stack). :meth:`.Sequencer.has_finished` allows to check, whether the sequencing process was completed. -Sequencing Process Example -^^^^^^^^^^^^^^^^^^^^^^^^^^ +Sequencing of Conditional Branching +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware will then never know of potential other execution paths). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the disadvantage of being not real-time capable (cf. :ref:`Read more on conditional branching `.). + +Implementation Details and Algorithm Walkthrough +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +The implementation sequencing algorithm itself is spread over all participating classes. The :class:`.Sequencer` maintains a stack of pulse templates which are to be translated (the *sequencing stack*) and implements the overall control flow of the algorithm: It proceeds to remove the first template from the stack and call :meth:`.PulseTemplate.build_sequence` until either the stack is empty or the first element cannot be translated. Afterwards it embeds all :class:`.InstructionBlock` s into one single :class:`.InstructionSequence` and resolves pointers in :class:`.JMPInstruction` s. Details on why this is necessary will follow below. + +A crucial component of the sequencing process are the methods :meth:`.PulseTemplate.requires_stop` and :meth:`.PulseTemplate.build_sequence` (defined in the abstract interface :class:`.SequencingElement`). These accept a mapping of parameters and conditions as well as the :class:`.InstructionBlock` that is currently under construction and implement the specific functionality of the corresponding template required in the sequencing process. Examples of this were already briefly stated above but shall be elaborated more in the following. + +Considering the :class:`.TablePulseTemplate`, the required result of the sequencing process is a waveform representation of the pulse defined by the template and an instruction that this waveform shall be executed by the hardware. If any parameter cannot be evaluated at the time, the sequencing process should stop since the waveform cannot be created. Consequently, :meth:`.TablePulseTemplate.requires_stop` is implemented to return true if any of the parameters required by the template cannot be evaluated, causing the :class:`Sequencer` to interrupt the sequencing process before calling :meth:`.TablePulseTemplate.build_sequence`. :meth:`.TablePulseTemplate.build_sequence`, evaluates the required parameters, creates the waveform and adds a corresponding :class:`.EXECInstruction` to the :class:`.InstructionBlock`. Since conditions are only relevant for branching, the corresponding mapping passed into the method is ignored in the :class:`.TablePulseTemplate` implementation. + +For a :class:`.SequencePulseTemplate` we require that all templates forming this sequence will be translated, i.e., the translation of the :class:`.SequencePulseTemplate` is the sequential translation of all contained subtemplates. To this end, :meth:`.SequencePulseTemplate.build_sequence` does not perform any translation by itself but simply pushes all subtemplates to the sequencing stack, only taking care to map parameters if necessary. Conditions are ignored as in the case of :class:`.TablePulseTemplate`. Since :class:`.SequencePulseTemplate` does not need to evaluate any parameters by itself, :meth:`.SequencePulseTemplate.requires_stop` always returns false. + +Finally, for a :class:`.LoopPulseTemplate` we expect one of the following behaviours depending on whether the looping condition is evaluated hardware- or software-based: In the first case, the template representing the loop body should be translated and wrapped with conditional jumping instructions which will cause the hardware device to repeat the resulting waveforms as long as the condition holds. In the second case, the condition must be evaluated by the software and, if it is true, the loop body must be translated and executed in-place, i.e. without any jumps. Afterwards, the execution must stop to reevaluate the condition in the software and decide whether the loop body must be executed again. Since these different behaviours for hardware- and software-based evaluation are similar for loops and branches, they are not directly implemented in the :class:`.LoopPulseTemplate` and :class:`.BranchPulseTemplate` classes but in the corresponding implementations of :class:`.Condition`. The task of :meth:`.LoopPulseTemplate.build_sequence` is thus only to obtain the correct instance of :class:`.Condition` from the provided conditions mapping and delegate the call to :meth:`.Condition.build_sequence_loop`. Depending on whether the condition is a :class:`.HardwareCondition` or :class:`.SoftwareCondition` instance, :meth:`.Condition.build_sequence_loop` will push the required templates to the sequencing stack and generate the corresponding jumping instructions. + +During the sequencing process, instructions are not directly stored in a fixed sequence. This would be impractical since during the process it is not clear how many alternative paths due to branching and looping will arise and thus where to place the corresponding instructions in a single sequence. Instead, each branch or loop body is represented by an :class:`.InstructionBlock` comprising all execution instructions in this branch as well as potential jump instructions into other blocks. This allows independent construction of blocks during the sequencing process. The :class:`.Sequencer` maintains separate sequencing stacks for each block which allows to continue translating other blocks if a particular block encounters a template which requires a stop. The block into which instructions have to be placed is passed as an argument into :meth:`.PulseTemplate.build_sequence`. With the exception of the main instruction block, which represents the entry point of instruction execution, every block is entered by a conditional jump instruction in another block and ends with an unconditional jump/goto back to the next instruction of that block. When the sequencing process finished, :class:`.Sequencer` embeds all instruction blocks into a single sequence and resolves the instruction pointers of the jump instructions to positions in this sequence instead of references to other blocks. The result is a sequence of instructions represented as :class:`.InstructionSequence` in which no blocks remain and executions paths are solely represented by jumps to instruction positions. + +For two step-by-step examples on how the sequencing process proceeds, see :ref:`examples/09DetailedSequencingWalkthrough.ipynb`. .. note:: Provide an exemplary sequencing run \ No newline at end of file diff --git a/doc/source/examples/06ConditionalExecution.ipynb b/doc/source/examples/06ConditionalExecution.ipynb index aaa783b38..7c56d281a 100644 --- a/doc/source/examples/06ConditionalExecution.ipynb +++ b/doc/source/examples/06ConditionalExecution.ipynb @@ -45,7 +45,7 @@ "\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", + "## 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:" @@ -160,7 +160,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/doc/source/examples/09DetailedSequencingWalkthrough.ipynb b/doc/source/examples/09DetailedSequencingWalkthrough.ipynb new file mode 100644 index 000000000..0a540af86 --- /dev/null +++ b/doc/source/examples/09DetailedSequencingWalkthrough.ipynb @@ -0,0 +1,853 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "# Detailed Sequencing Walkthrough\n", + "\n", + "This example will provide two step-by-step illustrations of the internals of the sequencing process. Note that this will involve some calls into the object structure to unveil internals which are not intended to be made in a productive use case and produce some very technical outputs. These are broken down and explained in detail where necessary.\n", + "\n", + "## Example 1 (Software-Evaluated Loop Condition)\n", + "\n", + "In the first example, we will emulate the behaviour of a `RepetitonPulseTemplate` to repeats a `TablePulseTemplate` for a fixed number of times using a `LoopPulseTemplate` with a `SoftwareCondition`. We have done so already in [the example for conditional execution](06ConditionalExecution.ipynb) but here we will explore the sequencing process in detail. The definitions of the classes are the following (resulting in 2 repetitions):" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import LoopPulseTemplate, TablePulseTemplate, SoftwareCondition, Sequencer\n", + "\n", + "# define a table pulse template which we want to repeat (including a parameter)\n", + "table_template = TablePulseTemplate()\n", + "table_template.add_entry(1, 'foo', 'linear')\n", + "table_template.add_entry(3, 'foo')\n", + "table_template.add_entry(4, 0, 'linear')\n", + "\n", + "# define a software condition will evaluate to true as long as the loop counter is less than 5 and false afterwards\n", + "repeat_condition = SoftwareCondition(lambda x: x < 2) # it will never require an interruption of the sequencing process\n", + "\n", + "# define a loop template consisting of the table template as body and a condition identified by 'rcon'\n", + "loop_template = LoopPulseTemplate('rcon', table_template)\n", + "\n", + "# provide sequencing mappings: condition 'rcon' -> repeat_condition and parameter 'foo' -> 2\n", + "conditions = {'rcon': repeat_condition}\n", + "parameters = {'foo': 2}\n", + "\n", + "# create a Sequencer instance and push our loop template on the sequencing stack with the corresponding mappings \n", + "s = Sequencer()\n", + "s.push(loop_template, parameters, conditions)\n", + "\n", + "# store references to the main instruction block and the corresponding sequencing stack\n", + "main_block = s._Sequencer__main_block\n", + "sequencing_stack = s._Sequencer__sequencing_stacks[main_block]" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'rcon': })]\n" + ] + } + ], + "source": [ + "print(sequencing_stack) # print the current sequencing stack for the main block" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see in the dump of the sequencing stack of the main instruction block, there is currently one item on the stack, which a tuple consisting of our `LoopPulseTemplate` `loop_template` and the mappings `parameters` and `conditions`. The following figure illustrates the current content sequencing stack.\n", + "\n", + "![The sequencing stack after pushing `loop_template`](img/walkthrough1_01.png)\n", + "\n", + "Running `Sequencer.build()` would run the entire sequencing process, resulting in the desired instruction sequence. However, since we want to understand the process itself, we will perform the necessary steps ourselves by manually calling the corresponding functions. We now translate the topmost (and only) stack item:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = sequencing_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " sequencing_stack.pop()\n", + " template.build_sequence(s, params, conds, main_block)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `build_sequence` method looks up the condition identified by 'rcon' in the conditions map `conditions` which is our `repeat_condition` object define dabove. It then invokes the `build_sequence_loop` method of this object. Being a `SoftwareCondition` object, it evaluates its evaluation function, which returns true, and thus adds the body, our `table_template` to the sequencing stack. Since the loop condition must be evaluated again after the loop body was run, also the `loop_template` is pushed to the stack again. Thus, the stack now looks as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'rcon': }), (, {'foo': }, {'rcon': })]\n" + ] + } + ], + "source": [ + "print(sequencing_stack) # print the current sequencing stack for the main block" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![The sequencing stack after translating `loop_template`](img/walkthrough1_02.png)\n", + "\n", + "Note that no waveforms or instructions have been generated so far, i.e., the main instruction block is empty:" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "print(main_block._InstructionBlock__instruction_list) # print all instructions in the main block" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "`Sequencer` would now enter the next iteration, i.e., pop and translate the topmost element from the stack." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = sequencing_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " sequencing_stack.pop()\n", + " template.build_sequence(s, params, conds, main_block)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This time, our `table_template`, that is, the body of the loop, is at the top. It's translation via `build_sequence()` looks up the parameter value for 'foo', generates a waveform and inserts a corresponding instruction in the main block:" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "print(main_block._InstructionBlock__instruction_list) # print all instructions in the main block" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since we've successfully processed the `table_template` item on the sequencing stack, we are left with a `loop_template` item. That means, the stack looks just like in the beginning (refer to Figure 1)." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'rcon': })]\n" + ] + } + ], + "source": [ + "print(sequencing_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We will fetch it from the stack and translate it. Since the loop counter in the `SoftwareCondition` object is currently 1, it will still evaluate to true, meaning that the loop continues, i.e., the body template and the loop template are again pushed to the stack (cf. Figure 2)." + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'rcon': }), (, {'foo': }, {'rcon': })]\n" + ] + } + ], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = sequencing_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " sequencing_stack.pop()\n", + " template.build_sequence(s, params, conds, main_block)\n", + " \n", + "print(sequencing_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Proceeding as before, we translate the topmost element, which is again the loop body `table_template`. This results in the expected `EXECInstruction` and a stack in which the `loop_template` remains for reevaluation." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'rcon': })]\n" + ] + } + ], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = sequencing_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " sequencing_stack.pop()\n", + " template.build_sequence(s, params, conds, main_block)\n", + " \n", + "print(sequencing_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Our main instruction block now contains two `EXECInstruction`s:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, ]\n" + ] + } + ], + "source": [ + "print(main_block._InstructionBlock__instruction_list) # print all instructions in the main block" + ] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": true + }, + "source": [ + "We are left with the `loop_template` on the stack, which we will translate in the following. However, this time the `repeat_condition` will evaluate to false, meaning that neither body nor loop template are pushed to the stack. We are done with the loop." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = sequencing_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " sequencing_stack.pop()\n", + " template.build_sequence(s, params, conds, main_block)\n", + " \n", + "print(sequencing_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Note that we have not yet obtained an `InstructionSequence` but only constructed the main `InstructionBlock` object. We will conclude the sequencing by converting the main block into the desired sequence:" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, , ]\n" + ] + } + ], + "source": [ + "instruction_sequence = main_block.compile_sequence()\n", + "print(instruction_sequence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this case, this is a trivial task, as it simply takes both instructions contains in the main block and adds a `STOPInstruction` to generate the sequence. Now we are done." + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print(s.has_finished()) # are we done?" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We have explored what happens internally when we invoke `Sequencer.build()` on our `loop_template`. In a productive use case, we can let `Sequencer` handle all of this and get the same result (apart from memory addresses of the involved python objects):" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, , ]\n" + ] + } + ], + "source": [ + "s = Sequencer()\n", + "repeat_condition = SoftwareCondition(lambda x: x < 2) # it will never require an interruption of the sequencing process\n", + "conditions = {'rcon': repeat_condition}\n", + "s.push(loop_template, parameters, conditions)\n", + "instruction_sequence = s.build()\n", + "print(instruction_sequence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Example 2 (Hardware Evaluated Branch Nested In Loop)\n", + "\n", + "In this example we want to look into hardware-based branching evaluation based using the `HardwareCondition` class and how `InstructionBlocks` are created and handled during the `Sequencing` process. The pulse we want to translate is a loop which contains a branch template (if-else-construct) which in turn contains table pulse templates:" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "from qctoolkit.pulses import LoopPulseTemplate, BranchPulseTemplate, TablePulseTemplate, HardwareCondition, Sequencer\n", + "from qctoolkit.pulses import Trigger\n", + "\n", + "# two table pulse templates for the alternative paths of the branch pulse template\n", + "# they differ in their interpolation behaviour (jump vs linear ramp)\n", + "pos_template = TablePulseTemplate()\n", + "pos_template.add_entry(1, 'foo', 'linear')\n", + "pos_template.add_entry(3, 'foo')\n", + "pos_template.add_entry(4, 0, 'linear')\n", + "\n", + "neg_template = TablePulseTemplate()\n", + "neg_template.add_entry(1, 'foo')\n", + "neg_template.add_entry(3, 'foo')\n", + "neg_template.add_entry(4, 0)\n", + "\n", + "parameters = {'foo': 2}\n", + "\n", + "# the branch pulse template\n", + "branch_template = BranchPulseTemplate('bcon', pos_template, neg_template)\n", + "\n", + "# the loop pulse template\n", + "loop_template = LoopPulseTemplate('lcon', branch_template)\n", + "\n", + "\n", + "# for this example: Introduce a trigger that can be identified by a name\n", + "class NamedTrigger(Trigger):\n", + " def __init__(self, name: str) -> None:\n", + " self.name = name\n", + " \n", + " def __str__(self) -> str:\n", + " return \"Trigger '{}'\".format(self.name)\n", + "\n", + "# create HardwareCondition objects for branch and loop\n", + "branch_condition = HardwareCondition(NamedTrigger(\"branch_trigger\"))\n", + "loop_condition = HardwareCondition(NamedTrigger(\"loop_trigger\"))\n", + "\n", + "# mapping of identifiers to conditions\n", + "conditions = {'bcon': branch_condition, 'lcon': loop_condition}\n", + "\n", + "# create a Sequencer instance and push our loop template on the sequencing stack with the corresponding mappings \n", + "s = Sequencer()\n", + "s.push(loop_template, parameters, conditions)\n", + "\n", + "# store references to the main instruction block and the corresponding sequencing stack\n", + "main_block = s._Sequencer__main_block\n", + "main_sequencing_stack = s._Sequencer__sequencing_stacks[main_block]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The sequencing stack now contains a single entry, namely the tuple containing our 'loop_template' and the mappings 'parameters' and 'conditions':" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'bcon': , 'lcon': })]\n" + ] + } + ], + "source": [ + "print(main_sequencing_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![The initial sequencing stack for example 2](img/walkthrough2_01.png)\n", + "\n", + "Entering the sequencing process, we translate the topmost element as before:" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = main_sequencing_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " main_sequencing_stack.pop()\n", + " template.build_sequence(s, params, conds, main_block)\n", + " \n", + "print(main_sequencing_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Surprisingly at a first glance, the sequencing stack of the main instruction block is empty afterwards although we are far from being done with the sequencing process. What happended here is that the call to `LoopPulseTemplate`s `build_sequence()` method resulted in a call to `build_sequence_loop` of the corresponding condition object `loop_condition`. This is of type `HardwareConditon`, meaning that all possible execution paths must be translated into a hardware understandable format. Thus, a new `InstructionBlock` was instantiated into which the body of the loop will be sequenced. Accordingly, the remaining templates which represent the loops body are pushed to the specific sequencing stack of this new instruction block. In the main block we will simply find a `CJMPInstruction` (conditional jump instruction) to the new block." + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "print(main_block._InstructionBlock__instruction_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# obtain a reference to the new InstructionBlock representing the body of the loop\n", + "loop_body_block = main_block._InstructionBlock__instruction_list[0].target.block\n", + "loop_body_stack = s._Sequencer__sequencing_stacks[loop_body_block]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The contents of the sequencing stacks are the following:" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[(, {'foo': }, {'bcon': , 'lcon': })]\n" + ] + } + ], + "source": [ + "print(loop_body_stack) # print the sequencing stack for the loop body block" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Sequencing stacks after translating the loop template](img/walkthrough2_02.png)\n", + "\n", + "`Sequencer` continues the sequencing process, until it cannot proceed for any instruction block currently under construction. Thus, although the stack for the main block is empty, we continue with the loop body block:" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n" + ] + } + ], + "source": [ + "# get the topmost item from the sequencing stack\n", + "(template, params, conds) = loop_body_stack[-1]\n", + "# remove template from stack and translate it it does not require a stop\n", + "if not template.requires_stop(params, conds):\n", + " loop_body_stack.pop()\n", + " template.build_sequence(s, params, conds, loop_body_block)\n", + " \n", + "print(loop_body_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Since we translated a `BranchLoopTemplate` with a `HardwareConditon` we end up with two new instructions blocks, one for the if-branch and one for the else-branch, with separate sequencing stacks. We also obtain corresponding jump instructions in the loop body block: A conditional jump into the if-branch, performed if the condition is fulfulled followed by an unconditional goto into the else-branch, if the conditional jump does not occur, i.e., the condition is not fullfilled." + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, ]\n" + ] + } + ], + "source": [ + "print(loop_body_block._InstructionBlock__instruction_list)" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [ + "# get references to if and else branches\n", + "if_branch_block = loop_body_block._InstructionBlock__instruction_list[0].target.block\n", + "else_branch_block = loop_body_block._InstructionBlock__instruction_list[1].target.block\n", + "if_branch_stack = s._Sequencer__sequencing_stacks[if_branch_block]\n", + "else_branch_stack = s._Sequencer__sequencing_stacks[else_branch_block]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The stacks now look as follows:\n", + "\n", + "![Sequencing stacks after translating the branch template](img/walkthrough2_03.png)\n", + "\n", + "The table pulse templates `pos_template` and `neg_template` are translated in the usual manner, resulting in an `EXECInstruction` in the respective instruction blocks:" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "collapsed": true + }, + "outputs": [], + "source": [ + "# translate if-branch stack\n", + "(template, params, conds) = if_branch_stack[-1]\n", + "if not template.requires_stop(params, conds):\n", + " if_branch_stack.pop()\n", + " template.build_sequence(s, params, conds, if_branch_block)\n", + " \n", + "# translate else-branch stack\n", + "(template, params, conds) = else_branch_stack[-1]\n", + "if not template.requires_stop(params, conds):\n", + " else_branch_stack.pop()\n", + " template.build_sequence(s, params, conds, else_branch_block)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Afterwards, all stacks are empty" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[]\n", + "[]\n", + "[]\n", + "[]\n" + ] + } + ], + "source": [ + "print(main_sequencing_stack)\n", + "print(loop_body_stack)\n", + "print(if_branch_stack)\n", + "print(else_branch_stack)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "and we are left with four instruction blocks, two of which contains `EXECInstructions` while the rest only specifies control flow, that is, (conditional) jumps into other blocks. In an illustration, the blocks look like this:\n", + "\n", + "![Interconnected instruction block](img/walkthrough2_04.png)\n", + "\n", + "Note that the returning unconditional gotos are not listed explicitely in the outputs above but always implicitely defined.\n", + "\n", + "In the final step of the sequencing process, these blocks are now converted into a single sequence of instructions by embedding each blocks instructions into the instructions of the block jumping into it and then adapting the jump pointers. The final sequence is as follows:" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[, , , , , , , , ]\n" + ] + } + ], + "source": [ + "instruction_sequence = main_block.compile_sequence()\n", + "print(instruction_sequence)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "![Interconnected instruction block](img/walkthrough2_05.png)\n", + "\n", + "This instruction sequence indeed represents our desired behavior." + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "collapsed": false + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n" + ] + } + ], + "source": [ + "print(s.has_finished()) # really done?" + ] + } + ], + "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 +} diff --git a/doc/source/examples/examples.rst b/doc/source/examples/examples.rst index cd40398e7..b3b272952 100644 --- a/doc/source/examples/examples.rst +++ b/doc/source/examples/examples.rst @@ -14,4 +14,5 @@ All examples are provided as static text in this documentation and, additionally 05Parameters 06ConditionalExecution 07PulseControl - 08RealWorldCase \ No newline at end of file + 08RealWorldCase + 09DetailedSequencingWalkthrough \ No newline at end of file diff --git a/doc/source/examples/img/sequencing_walkthrough.svg b/doc/source/examples/img/sequencing_walkthrough.svg new file mode 100644 index 000000000..9555f2192 --- /dev/null +++ b/doc/source/examples/img/sequencing_walkthrough.svg @@ -0,0 +1,2207 @@ + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + Sequencing Stack<Main Block> + + + + + loop_template + + + + table_template + + + + + 'rcon' + + + + + + + parameters + + + + 2 + + 'foo' + + + + + conditions + + + + repeat_condition + + 'rcon' + + + + + + Sequencing Stack<Main Block> + + + + + loop_template + + + + table_template + + + + + 'rcon' + + + + + + + parameters + + + + 2 + + 'foo' + + + + + conditions + + + + repeat_condition + + 'rcon' + + + + + + + + + + table_template + + + + parameters + + + + 2 + + 'foo' + + + + + conditions + + + + repeat_condition + + 'rcon' + + + + + + Sequencing Stack<Main Block> + + + + parameters + + + + 2 + + 'foo' + + + + + + loop_template + + + branch_template + + + bcon + + + + + pos_template + + + + neg_template + + + + + + lcon + + + + + conditions + + + + loop_condition + + 'lcon' + + + + + branch_condition + + 'bcon' + + + + + Sequencing Stack<Main Block> + + + Sequencing Stack<Loop Body Block> + + + + parameters + + + + 2 + + 'foo' + + + + + branch_template + + + bcon + + + + + pos_template + + + + neg_template + + + + + conditions + + + + loop_condition + + 'lcon' + + + + + branch_condition + + 'bcon' + + + + + + Sequencing Stack<Loop Body Block> + + + Sequencing Stack<If Branch Block> + + + + parameters + + + + 2 + + 'foo' + + + + + pos_template + + + conditions + + + + loop_condition + + 'lcon' + + + + + branch_condition + + 'bcon' + + + + + + Sequencing Stack<Main Block> + + + Sequencing Stack<Else Branch Block> + + + + parameters + + + + 2 + + 'foo' + + + + + neg_template + + + conditions + + + + loop_condition + + 'lcon' + + + + + branch_condition + + 'bcon' + + + + + + Main Block 1 - jump: Trigger loop_trigger2 - stop + + + Loop Body Block 1 - jump: Trigger branch_trigger2 - goto3 - goto + + + If Branch Block 1 - exec: waveform pos_template2 - goto + + + Else Branch Block 1 - exec: waveform neg_template2 - goto + + + + + + + + Final Sequence 1 - jump: Trigger loop_trigger → 32 - stop3 - jump: Trigger branch_trigger → 64 - goto 85 - goto 16 - exec: waveform pos_template7 - goto 58 - exec: waveform neg_template9 - goto 5 + diff --git a/doc/source/examples/img/walkthrough1_01.png b/doc/source/examples/img/walkthrough1_01.png new file mode 100644 index 0000000000000000000000000000000000000000..01c50126ccfa2b4324db8777ea3c172f545e7969 GIT binary patch literal 24567 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 literal 0 HcmV?d00001 diff --git a/doc/source/examples/img/walkthrough2_03.png b/doc/source/examples/img/walkthrough2_03.png new file mode 100644 index 0000000000000000000000000000000000000000..038a7b927af0cc8e64fc0c7a0d5d39d30ca27bf2 GIT binary patch literal 71502 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

`0B=&1?~{uM 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

g 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 literal 0 HcmV?d00001 diff --git a/doc/source/examples/img/walkthrough2_05.png b/doc/source/examples/img/walkthrough2_05.png new file mode 100644 index 0000000000000000000000000000000000000000..d0a5fe7e7c0fc06fbf4efcca28539c728440f8b7 GIT binary patch literal 38697 zcmcG$c{EmS{5QHuDkUL9gs3Eh%1|`1eypa}vv+5Z57{AfD99PrZh+p0t&xPRYO^&K(T?k_R5Ar{%O&o$H_{$yFP8wa) zb+~ZN-OBkq;qLA(Vt4hji;b1zc@YQai!l>290ak8P*YOW^N9T&=V|)2eeI*gLhE>5 z(u<~-I%;Rs6JH4LXI}d0e#460>fDZ+L!5`%KZIxPSZ=cv6A#{U;qg76E6JLIEN@>N zPrjeGy!x+k()XoSyjMqO!xv9E?uF_6h1i9o@e3EdeClQ67mljX_?KIXv4`^q{nb47 z-=CI}MAn>FS3Dob#FVL7uy3Kgac14oqerJ^XKA!g7JvQvweh89jMO0WjS5S#ONzR> z50>i-HSujpn<}ef@OMvlX%z4H|LM!I+!(P-{gpwR1w=)&+>Z(g2^pD~tRp_x)j9Q6 zt|$D1g4SQLx7Q!*PuDRv4m%YsLZyAjFM>zDX1f2Q)53(AjMw}YX=!QOmNXV=*D)Fg z2M5(XO#1m>Emx9wiEG34T-M@Se0+TF^L$+LmRtR6lX-Wa)-%UZm*IM!8(v9|zkJcC zFKd5yQ7Zr0ix+$7=;-(&RbR~JkBp8s?u++6E^1z^-ODY;t{I=U!23(ms#vlpjHDa*Rz`_@$&dARGBjN4R(o(+n;@dFU z>s~){?3mla%!@q^J`%O4uVV{U5<7UXVxaZ`VE%SF? z5Th6yz2DTI>p1`WEa7h?Tobr{^Q9b#Lx(EcEd0LyTb*mO;B1kiP1;{+OmWzB{`~nP zZok=y1pAIWM>n^jnWpdG8QIu2genClB|dBYuB#nmHM4MdzK(1BqX-8uqbM2 zWhpPq`79}znQC>lA3Po>3rQI(}K%wnZ3OqZfy%y+PHPA zfpJ;qX}kq~*6>pFg9kU#4YT+}M7G-5*}Zx9?nZjLP@&s+*oCi8_Y0G&b@*aEL0n&$ zpqG`E#U=LO4xLn2r>n9)*xA|HkbH`bB9Xl1iAFHO|Gd z%*?E0d3^u!Mm>BeFxUG{er*p)YE?tSXy(?*(&f`uT-Y;w*+yR$#jpGjGtRbNe}_}*?o%m; z(?ouM*W*6f3t!l;a^f(N9|sj8dG+72i!YII@;2+H&ju`$jY%rZgpRImQhnU9@Ar65 zd}?idQ?W)RJ}7wX}u@FJ8Q; zdzm$y3sAb#b5C9wur9V`JmMes7fA)86!3wv7D9wkcle>$9fYx^*Zo`{Fllk*tIS z|I6Fi+1WR)@_ssZXsPeEXny|c==WD`99vv{*{zywrt=Bl| z4lf0@(-wc zbk3T=aY~7a)gr3eM7M^50ugOK7eKC#pe*g-3txJ?!*Ac#z4S3Py4dnzghgvqROqN)zoMeml7V7bjE z8l050ThxO80k5DSUA*to{+(Q0(-TFL&Z5%kZ?RMZgM(DWBjK}^oIScMy1KgIJC8CE zjw21cD5p-I8yL6;u26gy%z_5TfB(*(xl@sC^Kq)DVjWSwviK+JnIS3~w$OUQak}s1 zi&w9Na{eqV+)7VRuPjaz6&n1wHKkZ`E05e30u}pX%9*6?j~rTG?HTYUFlys zc;h#pWYpiSIrHaF!6dF5faK<@SFb9alarHGH8hmYo!f&tN9ZYAinAIR7#Nj$A4OBU zySy;Dn~#s0k&*F;>)3W@XJ~p4Bk>hC7UekO>s+yV_(?y&|m+oV(V|q5?>gabK zgQjL?XSB8bW279Y2^8yxVe$kGEp6-N9(|vbLLM|KiHTdcZ*R_u#R)8b$=g;Fcg+3X zlP8;qshOETqu0fbzxuL8B-Wh_<(?AJB zO_w;o{(PKdmOgdt&ZSNEObAh|G(y~nTo%-MupAGpGLz?ke&!{6eES3j3sRpMjB9m{s=R}N=CNR0z? z+}xb|F4wW(fq`>JjvOI~g~^1{&Jr&+!sCF_i4z|<>K;FRDrsxtnwYpuURcm5eSu_} zTNchwOZw}ye;1n>_$g~l0IqirnB);DJ8MLFLYi=t^9u_rYieluA~$j!bJHvEaQN|t z%F4>hV`gB}R&JS%US7+_b$=HZtwtIWO)rb^^9M6KFf%jn;pcyT_T7b$(9qO(JirHp zc6-S#rcebXkH1q^cg{bP^)k3za_GqxB^uy4F^l#Ab7l3nh={_Wpf<=DRDYKE;iN?l*l~S{GFD9mrK7wKM<`4Jxo*L7u|M1}k^CX+7x#Q^k{QME0C2{QP#LP@{8}|Ud zoZMWi3m1ZM1_gW;_o+~f4V7Bl+19ULuWoTf@E89*`Koh=cF=9!TyX3Aud4d`yI%LY z%KXZdJ8s^j=`3{JjJ=Oz)hm0GN6tG$5(VV#`|z|kDm`WXe}=!gbhC+=rp#6wT)!^8 z@ceC>QK_I=k=tPDWXF4kLr-3x9!#s}H_{hK^UboasaX3r>BlZ{X*;X1k^eFG3CGbH z)o9=$Cs8#PUcV86%JOpmWf4Co!?^qRnUbFyxytkL@jbk{Atko^d{qeJV<`vjzW)Bp zIT;K;fBv-XDwOd5eDdVO5+N#owAZa4ZZW6;b)7La-E#Qw;j2plKxrIxtlPI+HY6xM zmbB+^`~4&F(AwHp^44n4tvAzrZaNqAK(HG4mSVcG<7o0$CJ zCh)4aP&A01{s{S@lUjOvrKH$4vx!ud`YgXWU&m@*6(%D%Qhl4PSnW;P4C>jH?ozYV z2og+`8u}y}N9m^^oGnQJjrFLDgKeLLH-g8F7qkk!AXx#ID(z)j5jM2feE z(Cycr*mi6>DA2cuzQ(L0_%)x>BsiDGKCRSldwurC)Rf~DO7RnS*+b^^lB&Zjo@O8V zsT%O+QLTwzuCA^AD`xaS?J9O2930F+kEZxfz8LQBHfLRXT+pu&|;gj zEadAi^i_oxucY0$*82Kv(!faD6+FW0T}4tCg`(7J zJ33O#(}w!#v9_|;u}+9BQAV?xL>{6g#SU~RPTp^88nuG(NVR@k_B#h4)Ktu5|?WR zJv}|o099ud3s%L1jEpoU6}$BR{;h#sEJDBY$eY$hebk;$LLDzPIXR@S36v~P6cz8M z&B@8R6eke=A5{C&Awp4#I^L3`!VsYFdA-f*%Ay`_W@Ka}orAM}hLtC{DTlc2HmSDY zw-H4}MV6(JVgm3lw%{oA`Cx$gjQknA~2%Y--FSQ7w?gw9S=#iRP6QjBMuoe#NAbOMG3 z2M6a^eV|QCNzpcv1dj9e@rio&4g06%y4;Rj-8s4KwJa-uufOe`)`T0kxK7J%I3=ZXS5RrygT0E4M4hbi) z36jqN#09>4cev1fa_i;Gmw!`AIQwhvtkYg}&Ou$Es{>l)Y|At|0cME>K;I20FIPxO zPwxjDS5;FBc>0vX+uQr$lD3gi$lt#n_bfByVA zp|{mYht*Tpun16c!szpdgJ2=O!^0ngj0JCmkkk|<7q5`?;ss4>Yb$!ri4t1ggAf1w zowgCFdKfAN<;0c6fwtdOTfg{h&L$`(;);(w4zq7jX11iu*)oKwKPG-qo(O zG(nao)I`7Eo#hwnV-<0q$5z_GJ@3r<%(q`8?*$;z{L}darza>gU?;l$VH296&={s! zPiAgfeE1bx%Jy8=>Jw0Ao9Zx@sp)C*wSyUW$d2tFLdm&Iue`U<3?M3C-3C6a=gE^N z(^7Qyqvn4A(dBUEbf5$GjTW_-kwfjscc0|Oo}lqWF_dUs_}zZEv&cQGwc0m^uD!jT z{MXN)KT~pqvc7m|fEz{7R{eH$LjSa%2xv?dA5?UoQ=_%sp2A9u&35UV03U`0{jI zSnlPv*7Q=q1}gwx@RKCLu5&5=VEoS$5)$g?K`=wY!}S(FPp{F+t*y9JRaIG{V3LXo zDvLH01{7TD;rh6#g@uog586<2V&+~}9B|;PgnZQq@=x~a($dnj*;D($X-9tM{<_?5 zp!*7SYwFLR6JWu(+HgaqQ>Qlj`ubjReoecLm6aBpLip@k8V(K)LNH=D_9*nlk9WDe z9!y9)roHWMXSd%V!+8C^efvmc3t2%g*+PA^EsF=sQvXlRsgDLboCMeb;~?Q%S^+E947cXB@6Y~>Yw*irkYiTjuy?ZyXbkJvc zzT(?AhT7WNzrWvo>*?zY#4)!1JJn0~ZzBW4t@wDJ(v_K0`dqZ+Rw&1Jl4}l_Z*}h6 zO~&2I_|pcXGGAGImThcoAB9{dI*-o&ZfE}bRN@8%JmotaK@i%&ifJG4YxcE2ii)y= zYV#&LJK*l!tunH*(;pb*dvFtRn?8gx@AH@kB7J`e!Q`Ilb06^v;Yd2ZQIBf)O8Y&4Uj+h)vJBr`CDCF zTmbs{4jt05L? z0EvN#3Gz2_h>>sKyxBzz3=Aj<8NA*_G(%}y`sTNK;_1_;H2$Q*r&t1f@*+L`6shiL z$t~W5OuN2gH{aE{DHP^5FF&a(KNJW7adADXRVa!Z2`C2I--^!`lD%u(F8sn*eM zBh*3mn}BOo`6BNr@g-V)2tH$LD?q9n#62)qp2Kg?o;{l#jJ9aXcj{LaX4UP;v)?Z&s7MAT$dWaNg+}k-g)UmUM>e&cs zm!T~e{r)YvHZ?czAtf`Zt2;GgB=11_(1cO~rmg~_I<&Y0KSIhDVaJajANjY?y$=wa z>2~#OmwWg0705B4T3VtsG&R)(qweFP@7=pc%N5^N0aYax9RQz3fRC?Fvq<-1S|)e5 z<#gt0T_y(t0CR(&u<#zf=jfI*Gc$a|i^Rl=q8|70pC<|1=9Dvm*HOJjYwmEGUI#mL z9cc(ahxXum`0Ux~TU)uF|7y#^KKLa_!QQ*JICCDTBq1k9oR2TSgN>E-K5($zrAss3 zwO_v`1ClTk&phfDWU;{N>gxHk=qS!?+WOPnG9F@72>>ZG-VZw%0N_qNxGhEeEb)@6 zJ$LAtfY9?okKv)A`#5k=vkE;@a;Y2SqeRD1ykpME5t^JiuT&PT-Cckeg>Vi;LjmBAAn z92a-1+y%pg0K^B`FcBmuy`iY)R;ZMM%H5s4?Y=X$`)K@8;Xj=6gEU8#0ED+`EKbg+ z&@u+(S^b~gMpu@}CxY=1wTuaw^;BgrX&HYH}g?2I5&YhodqV{Df zDIIzeP9E<*AFyj`1>Ab3zcb5|Wt*!^D1i}SVN5@=polqg)m9%95y^a}^4#}fR8-`R z8|z4J0r_Ig%oi(7mMol2K4Re4uR5~_ngMBj|7uuma1<(`?$V5+NV@GbZu+gMp>gm2{Xi%qlx)8!Hb=BkLNMuC+U`iz z2JizC(T0YGjx;52#vQh@x4#1pzw!6-?C3foFlGO#Q>PRy_G^1S%d#lD3$P3eNz#L7 zyVd2(btOi+%2rmqSG!B;Ei5cX#>Qr5P>G65N<5dDxVY#QrVAFPrx{=D-Md#&n6-aq zur41ez33$9UaY1*3gOP3J1@;H>z^?+{D^MWJ3f8~@)fE0K=5!CDf3=*7PctesdN*- z$eL2@IRY96U5YnKowL!UAo&YkojnCIFEMwPws;y;|85qzjvl_UeSs#1!2K*C&xx}S} z?LtE7#{UeIp;-{+fCg5jE00miK6G~O#KoxFLxY1y!8@hZc$D_<@Y$9=vuKwm4|Iu`4SlXFHBZ ztR^;d0m5J4>n*{%4qbG_TIuxk7 zN9R&ZOw4T@wE(}**4dnYWZDKzKUWuI4!`1GuB<#x>5)#=ql5XPy5~N}dIPgKQJ%Si zS2Ynl5kN}P9frxTUvJTUsS%(jSPiqMcWlf!$wy6X6O<*E)ue@~sd6CgUouT|_I-Ck z--B`)WSTC1p8I67g;W4#JnLR(tDZisj2a=T$^CS2VuF&=adjh?^fiK5feRRDP}7ob z$orr+zx&dqOODRY$4yOlPIQ-vjz~v}eil-pbUnO(|M`@|Z}fjs1Ogb13c64mbeNx? z766lFpspzNXP*6LF#E?(p76@bazU?XfJtO)VirD0DY*^Nsls9mB{U^9wW7K@S+VrC z5+7kZHFX8s4Yt897<1qp#g7gXrl7?OMPmh%-DQ4v@)QQ0LhjyGwzEs^iC2KsfbQM^ zd7CzCa{r|Hm5nY#Ujj7vKST)`UXon}_Yjki2m-ulYHFfcw=$5Fn~{;h`TJYU^I9#9 zy_2gUAt61vrOZrBQ^WCol4E&o878+#U9YUJuCBmn0=U_E6qVx>XnT9f$_+qM2g=hNiI8MTJheO%);$^+$|CI%}($&?~J2DcIq!Q7G zwJI*gWpCk@VFz95m)&I^rFer@(Zq!Fa_eixoRkkAJ}@#f-+<=xp|O#XAWF@lGIFnVK2HA!_s>G2UKK8P}%BMZ@d(5%2& zf+6fl%N`lbUR;>${-`DYud1%dYe8iGcl$c*&7etYirdqbv1!PVLFn;UJM#m4|1FW| zJl|(o(syZeA1waOBG&rO&`3NyJ+1JA4b9C}P~4m#;fM3cb5kgk*seVLj%`d#f!Iwp zP(JPqY1ykL>v*sITVOxxyhlbxM$EQh7j{L@LbsoalhZ-}GLxHx7!c&|t|B(zuM<$& zVb$J&n7B(uW+zJCr!QXy3T1%;B(MDN2Uq6XwTr+ZB?~jOfj1D$&|s`Uebtw3IRjDi zL4tyDa4WmIxOjYK8NYn}N`AoCW<{)k!9PlUj$JIfHmb7%N7N|y5(_uf*|n8nc>w`| zauiDPTWM%$9G~x15oWc)*(WLQ^|`SifOoR&;w6kAeF!aXB}lI8Y&-Lvw)6045jbO~-mC#9@7B`Ny1MHlK8q?U z_Fm%JRFC2_pKI5|p?W<*OLR8{wzcajbd@>gnbPw)O6Zrj@OJtpUcMzjbS!&#$1@Nv zl$-rqTo0CHzG=`6#^Z^8?E=0U#-T%NHf zYXhnCrX6fLXJd21Z)N&pj9Z4exO(iuuj9b-C`6UTV5VVr?y!WsN{hU`Kq>JG4G}nY ztf-ZW-(em8UERiJuuoh6h*|T&!Cm*a29wl>)*W)9udJNGiwnA68ar%fm1K<<)8k^NiAXoJ4{LMPeDXzC@&#? zZA3e05fp|bGzSkJ>@3fF`5E6n3bB@6Zph(jT3^?TrDAxV+B!OcxW7VQ9NORRm3I4` za$oiS5@`JF&!kfv$6?RFD>>*nb546=xOc9is_I4kumxXa0ywnmYLPJO?cU$Ng+o$(^})nBI-{B)J0bzq z54v7F3vW19-j5rSkEy@~J-zLCSC;w>BJnpY&X#2v2?v*y$YM2VM3rMWz=x41(Y9OY zLWh|3j6dQOc$??y?*L*=@8^4m2%K~qR2%fM6VUn~X*t5sCl4n)IvFblI=V{SDEJym zq=W%5ibhofwiAi0iNxhr@x_=${ZyPzNSGy`^YinkCK=3M z{COuo7O-PV!qMY;YI9c~yj1e`mH|qcURni$s{Qy;rPrbsHnYnE-=uf?Ao%{7tn2zd@#imIB-1{Ni;HBi zC1ba^jg3v@qesD{{tPcJh9hcvo|J8`?lOC@&4Cuu>{NA;TFIMpq~N;u|2@!_wTA+Q z;ql>%TXB|2zz+S#5(Y>bSnqlL`gKy_LaL4>bNX-Ez|fF2E(fxpe_oy>FxhP= zy3Xk~>&k=aIi~;>s0m-xJ;+_Xuux1_AMDc-gBo%~TKc$(%7*cd_aC9fPUGfM^3dI> zNYzpH`gVkC0^h%vGS0CLfF9$$JpP`}@Zm)y5!)1RTwuA&5Y6Ea92QbGU0`=KG)1n1KcXrz5`=R(55D&g@kZr^?rwAvCx1VALu zGE^A5!ow`(ib2KOw};3LOqGCzEnC`d+>-A+NJo``jNzXqzr{f|Y6XPv`kU&X$)5U8 z6fk|N!JmY5+BV|n8>@9$cVP@(t=_r#V(yhz{1DE_=&Sf69S}`8U!us%-6FR?Q4Z<`K`C zJ!ArnLGG`AG#eyKgvWOSv2ve-1Ppz!SzTiq1f<{e(uuzIJp)0 z1O!q}3#ru^ew}DZkFH$7mG)pGsH&>^mzBv!PYe(5dy|`&rwk)#8w-p6FE^w^PqY-j zC6yR!#M1I1!vGiuLc_xLOKNq7MO_XrW&J2Z8(6Z4%0o<{G>AeThw?^>iSS~1g@w1^ zFX0xV&RxFa;`1swnTh}!*gjM@teDB2lzBz&BAoxK>gvS&{KsEIzgUWy3*n?fT^s3m zFN%Pf7~&pRe!NMn|HUGGRZD0W4s!EEnfP_`(v^}tS$&k?b zK~e2^IiIv^euRRBMSQfmwst~;91bFyqDKCXEj5>4RrLLXw@hlu zy%;2_&B4@=iHV6!pZr~3{_yiB2guGzxK`8MYpZOilPBQL-M@do0azobOLB(A63}~l zt0<4Ug-+=91=Zqx%9%8rm8 z?be+kh;r?e^JXXGUZf`kl(H`6_ZaBxtw)dkGaFz6Bw3XC9)V&B;W{xjH8f~5TV-|i zdhBDP0_VNY)m{O5XD$)*L)$)|l* zP++Ii^vr1KZ53h{;79(-QJ;rkrN=$Y4tNNwrFa}x{dX7vDS(_8ivY%(T3h)EaR3Mr zc>BLd**dcrNN@4)-v(@KkHJAF3ZQP1d$&(Cn%^d32PfxuXii$_hl1VmCr4)f+8{eLLz@bNCMzTi@G}2i0eMP`qa~sUW|KZCsYB_2^t7yD> zr5BRnbsXBodOK=svE64FdoJIbTGy{zx2|F~SKo8~_l{@sep{hlV5{io|5b)?rHCKJ zq1zRyO368vrQzl#i7YV{)Xj>KZm9|^Ixkb`YUD!euK^$iGNc0`+H83LTTb;GZEwOu zLK0AzBUShC5zX+n7~!wCD`UHb?+%#TlIGjr4yNN9odBzH(& zVW&#Kj*}V>QzttD72>Jk%Bk{_k_KWHTAJ(}9FTZDlm5;)^dQVU(AQV_HQ+^Rsv6M5 zE3osFE1denl6H=D#||B0LJcALB#Iwu&W7Iz!XUwL5=knU`hN{__@6Q%w?%?0(F1TX z5d=V{O@$1JdBP3L`Yx-?+}D(R3LRqua(*GaCxVOZ+*hZO4O)jr7@V5AAN*+@#6Ngp zmIxq#UsQnvHw$#wYu9zu)`k)dq=_{Ov5>|eEhGKytFL8G=s6{~5p?wQKHoEoos8;= zCdfz^(SZJ>Z!UF13j{XzQcDW?$FtcJaUI3 zzGxY_={y-;20BrXzL|d7*H?`0*{Q0NORpr=+U&ymkY-wwPhZ{BNADp-x0Usp-%<^fY$bPK;Sbixz2(k zmirUlUoY@KT8RRroVYO(8=)RfLA*4!$2KdduIi@EbLhScrIJL^V3mVS$vXQ>SC=kp z#7VQ@8t%Lur(N(A>O;TVN6g~?=`Tvh^d|rOpPem)VX^mBu)3YPuU&t&&f>)DB8Odq zMvP5VJ9ua3(fe>6XyyPt?qy|(whecu=?jsfcGROsGb<3lc{UP2frXT16O%eGbQT(a z5z~AHa042DfD!=-34Ocx1>77pq>Ve|ailPfu)Y1~&->^Q-y{zoegKDUb>X|Y@JpQd zCTtfa!WKTS%<|*M?9MJO{c~TB9XZkfiORzbu;(yU0-8u9D72I)KI>ZMtkEYE%7(2w z6RF`JY6-P zieqDvh7YXqJ*>BdhILs(1>m+klkw!6az#;W2Cb@RB})F(AG-!+re2vcb2mKv1zM-G z8;~ZMy@6q(dtLaF^~^wR;KFYCf3wVtjHFoyqy8UgbgToK*e(&DtpNmE(epD&%8`YI(xjmXw3vcGH)*kT`z&xRyuS$9An-b(xtx@s@*c^ZE>33f2nx5Ks}uiVwu6|#ZMw8()2 zdohVZtpFsCSK8Y6zT5W{s>MK6S(=AMzGDEcLKR5E;I)w=?6+j-@Ao4k8B^2K|E%1* z{T@Qe=-5~jtjiNXAfQgkSpM}2e39B%aXWN`97t7TKeBgIC4k1e7!9HD{)$|N9AKjgP~Er18gIJJX+= z7!J6t18a;b0dij>T*3W&_XdRsR^$AKgJ0Knb;SY7s*@HQU!q6dxkF?=iYfsR<2z<0 z)Hx-u>;f&ASTQV_w6?KPGckz)l~9BNnh1FP6!}4zVfCeH9=C#nnFySjBq07K+}@EJ z407mKO5_ee_{2F6U1}fJ^X=QWd?qF)Nhi;VM*KOuvl#r1=O86w}PrFg3|hq#vh8?o|HDo zIdDZi<~})mLSt~YgLUyRCgv3C+8m`D33k-pp6BTzlqXM~kOnuJPT-@jA&k2>5?aOb ziv!Hm3ZTS;?G(iEU+C=DDu$X{TU{N5LXVf2{;jK{17dv!RiZ$3Pl3l}JG+(wd2JC2 zoM#zE0YO1Nq@}Q=*O0d5TQVu8Y5-sKoHH%F7E0WUh={P{oVi>uHn)du5+_*aYzHpppt9AS@gnvRY~Y(e!IaJn9m4`KIG1v|ESm zt*jIYTjWRr54BW#p;FNJlbPgaW>aqJ9n2g*)JZfQ>DRFF_J4i0e=A{M3L&!6*s zc_zyVj5<8%0}e;M48*O7xXxx);hyC8_8qJ?HQ~Lf=WdyDl`ThGhNyp*a zq2W%=koqn#Y)he^{#h_{(Ryq^PPkr5=*^HNJoAuME=PRc!wzX@B?wQ@zIUf|Akjih zAr+xWAuqKL~zPk^5g*1_kBD`}gk?C~3?6eSM?@fnZN- z!MFUTMZU)o(3EWiBwuz4Y>3KE(1r|K{;1ppMhm5UA)%>3E&U-l>pXcT1nfBnH_ z^o0!sgmc3l-8q+pOK53gDEG4?jq9N1<^BYPKt_r%%rvba=k5?kfJD0v!Hpw+t1^JG z2fgNhOP86XFbM8=p*vU8jbsL5S|P|*AYXIFF5ePbyxSz@fNDIlXIbCNvQtV2Vocv0 z5Ek|rbyn1y)%nuWqJNK{q5F1Nm`+fPYYl}`YQR~b)#4yRK&9w8@Iv@O?KWoSb=dO2 z9UFhAX9+xf`jn190I-5=8uPH$*AtzH3W|t`%*_-@OK>e9*z%`|r6mhS8hRvAMX@cW>8I0-BC>ntiH9zIBhTkY+Uegu$&zyE)8gEy zCr{1}U)KxB&UVU>L{HtIT@Y*HiZ|1G0e>nOyFI9qUZLSLnIIr`Nl6*n-L9^vphB~q zn=g`v9jcA#TJ3ruzj5G`Lmq2ZmtAO`#Vs8Qquni_GVA%6BXlBfXGL>%j9eBatYaXF)_AvXN+Ve?L^Z?xQ$LO%vfK7*CAKW z!HKG}tRZa(?-7^-<%3Ybk>_;npijh*9pT^YyR3Q79nlL#W5jDCAq>HVp_{qOE&F-- zz+~RNNk3OIe2EG=F*%b?${UJLy^AEwT%7-#1NxEgw40WJ`^#lBSX<2geR7k9yC$g@ zG4@2`iE0oK6~%I)KDIrf@YfAf@iC@#S>ed2;4t*U8VM{OYr73_i%y4;68;}UWC~^2 z%(o;~&c|5W9hVHykvb)-VMgwWmoG2eki$JuG&bfCF)ubscU-3c>5PiNsZZXwXU|4+b?R~` zF$BTmJw?^#%*W>qV=LeHpY*rZ_Vyi$ii-Je;~WNA=3ncMVYrL@Ac(Z5oNG#gddqk0 zSj@5y;!v1W-~uK2i&&lRWlzsGqbpa0MP%6^W<^ z4w@KN+%_NsF}KOk3Lu0q&>H_PD2G_CJu>- zB>;e*!E&kbMK*wfJ`ASASjg1ak34%$ssw}z{xkvmY$6JZid^hwv=tZc{U8MzM7Y$! zuz*=dK!S!_rltFeG1esVNq75j+~dcpK(I7=TQ!{B-1reoBExmWz}VR5beqMQLHrOI z@WVtGK6fNiBCexNLBteo4q_%QPSe2rRC!$;IW#TQs9x0d6lf;?W!h z3Uz&H)~=)u#QP3joz$wx3?qFX;rA~Hn-8Iw zt>knL^b<}A;Y?|AgdKzQftV*=hg5+IDvc9H5_2xK&|zH=#2CDSAw3$z2o>X#Kn-yP z>l^tI%z?Ov#=q^#LX1NxdGJv({ZW;->^!m!p@rihL7r}SzhE>8xNsJeKFB-X$jZuU z8X-72IsYy#VU|hZ9kFjFE$b4zsNopQc+HVih&t!o$Nu zPW6-12oSmX(QfhjeJGwXURXv91@uE|_=rs18`ob3q-u%jfWIS25j_(V_3e4MAbey~ z3r{mL7z1GJ3)?{0tZ@6j)3FKwf1sUjFcCCi!LGfd7s9hpNEqP{n`Ec-wT(#FmXoQC z{u+ABSZo5|Kapi#B8C}d5Xp+K+YPU1ot_*oc5DrJfHWg8!xaE+YPYB;1Gx^Mdl)4k zV;|lKV3yxOwzLNY$zRFpm;HmE)qZmIc^Hm z3_>*zFeuwdfZ&7kl0u zz|0buz$N5%la^PsR0eNcGiPJqmQgr+_DQ7yf07%T?p+8coB5g737Y&MJUjs>Z{gHo zxWyw6p!hG61r3-qukhblBYz7F72>5OIZrl=xq8Hb5Xj}|OyI`^FQPmZ=n8NuWtI`r z-w9fXM~ZluWv&Tnd&aukkV*B4ul6_^-EX8cnaS-7j)MtT45i{5@riaoR1E?l!$|M_ z1vejZC;{PCk)jP4z)_boe+-%~f=62T!s zN8*a-CvQ8BHShQE^4blgfnOxNouBOf=2{DSO)6|a0l`R~f)d`sfroy~1oy@t-5MhR zb%yhy6~h^ml4=+mUlqLetMv|i%N6B+?HH1P?AHh~-<`rk&x;}k=cjaBi(e z?{x0ktB-i~D-82F{don~fTZl2@p2`KqEtJMr@6(1tgdaI=q%XHerQz^Zo+23v6A^l z+qHAh2@*3h%w9z+z-s*T^{c-0p{VI^%D^EIE7es@4PK?BY&`TtWAMcC+Bj^O$D7M- z4|VZp9lk!;ecUJ55vtU|-c`2Uthav&clys*&1`9Dd|_@xx~xe|{|5m+)dTb9{n$LN z##Bq)8dyJw@a7$Yy>MpZZ>d*%fmdNrp#}=N{@L-%gCH<>B$q7^hJ;?l0NP-5_AD9x z0t(;V-`m-ClsQ=QQ}4Wd)jHmVF*< zfrYZpr6&j>WALE{;(5=&z#b#BB`lE#5L#kV(hcCmN*G*-&f^jWON?BdohuD3eAXv8 zOKgu+tuj$t0Yp#%go9nP84uxE;qki29sfP|-`ckao~%3e-W*cn3*B`C?!`uR)lg4i z38gblO1b(uY;75O8}wTK>K{nV5m5h1b0AQ4+mn!*d)t`!ZhTo>S^YE_JLK_7?wj;-Y{~ptpp%i-jE=(>1sO}v`ylucYN{ID0%B0;8XO+}MgEbr z-{UbDSItdLePH&g_i^B8rgY?u$qbQpqPBLbo--=e%HnYRQOj}yu}U4tf~QZPw(bI8 zJJ^2;_4WOg_R5qL0SE;Th##0Tnl@^0nEKc95{q$+YK4sM^ zP5RhmU?4SabyIu$696v$#hEyFv^1o0v4v{UXw=#<|Flt|uNYKwlRq?+sOF5m!fM!bidK8L^8rvKH2Of(J*5AOzU-&?m*?D64)bI3J{COg;~23#a53 z`2$_?K8icyL`|m7>quwjS8Q;K855nUF#3dxA+b_n4o(F(lN06-r1Ae6H zaaltw2Dx*n*{PpUQ_dv)DRuqDN|b}^*?Z0nB!Vzt9G(|*{4K5e0^7yFCNEszS3RDn zos!`Wg`d!VGP-$VyjsQqNf|s}2!1?}Pg#}IItBcZOj3Gd`~?qUc&&TiddH3@e%#;2 zNsY4FV+8X)O7?L8Qq(Exh6WG*%wzrufl9prXp<7pOj7lz{eRLQK%)bpVB#vmMAqw! z49vzR8W^G)Vy~`qarwi+B}I^r0V0qmN|n6fh5AP{FJ)ZrrPY>&VL@|?JW%bPkgjBy z@y@Q-u3@23jmk%Id1{{D3dW4T{pknK6|wJ>q= z{P|?1AWg%S*Jj`Mr)fBXe?So+32dEtJXqxB3`}W;J?o3=#@`AT_u|QTzN)K%6P5y|c zc&Bv%pzsmC)75NDi%=^u=30lnd{AC~ZBhCJjt9@llACmC{bjwyu$V?MvP|S;XIsJI zKxDcW1e=jCGd0~a_e$f*adM{|1uFQ0P5bl5k8K40k}uT@aS-YR@F9Gk(!~;=Ww)_k zzjRS_z*jCJcZ2NaMt{Av>7e$Z z^>mi{6d8A6Z~SgZT!#-uKEUD3vxg6>07NnR5;-(9v}Mz#UJwcxO@F_*4I?K5sCo^o z6QQ8E*w`c9e;v({Jz6{l!+wZI<;E9o20eRMEp_!kgz431Izj&P3konB@S?)6OB>Rv zGFQvHk5VZb(vaCP%SnAJ(C}=ztAJvc9kHYb%$xb^V}0JdJw=c`@PDtA#X8+=fWcQ9XAG{a9}813Xcq^b#|<>C89L zU#id{Kl)3$|4zgwafNfk2k@@niO9J3u*x;oDY;Ry?!jusl7ngO0kKjoY4!e&X;{+h7f<5```%A;%d%Pp( z-(vIvA`1R#IXV6m)@Jfl+(pXt^faMu)6^BMiOCi`O(OoNode8oQh&z)&BN&Ew$a$A zs3=lQfy1i(>g*qw_y;dF3*4*10O{Dd8@Sjl+7b0dZ{BF{rEjmZ#+iDPn;V3qW}J6r z6Q~-Q@BwtTZGW5m;wnO;6yIfgb`Fl`*wv1%u0fb9A)i8mI7{|3;9OYz8wr&EU^Eh> zzo_)~nvt8CobT-E@rU?Q@#6ffq~|~@SBr!Lnm(DJcx_(7L3+Cwjv`}REGoul&II5OWOxMjS~bu% z(o{jPA&?hO<|Q;t|y*jqRrm+b5sDU@fJ z%VmNN2v)!~yfXRKP$=ii#C~Bvr^mQ{TM*rxK!z$Xe^0NFt1j zm>3mc=P_)+Mr4F?=aAs~-}`$=8H(xu-QU$ctnqXMkP}M;fpofCT3C?HMpxAH5(&VL zB|wde)SnzrB&XF8WyM1TRz9;j;0~^O7C+Rggz&;mz7sUb%hxCfj~eCJMurtb7?F^k zL|LFBu%VkD#XNo-vW5p~RG{0uF*050U5M6z1 z^MM2kX}bG{|4sFt!1Prmu?kVMEl+?Cdon_q{%O2TM~Q{5g%#29N=HF7WsbTicbnvEt{?siAQALl(kVz@=t{ zWe+I3%Lsvo5dHu(Hi#nMe~S&1c2lqrc{1o`VCE-LuJ@cLbq+iksY*GKt7Y!Uv1989 zXwRf36M7f$6Vvw!hK6hy?Yo|thk=t%#T#9X-=Gf#Ls`aseq;BYU#%TeT5uV|P_dFQ zb~|VN;=d0#IT?W_Lo!*`LAd%PhtMDU7JHPLAg5Pw>qBP%V!aWaApGHH-FD_J(Vn~a z0e}2}M^{+*%&|ac7Wj-u+D#)}(F?G~E^d48v-L|X)t9=LrxOFgn_eRJM%93*F+z9v zSo{Q@!7>BcM0Bqnzl1~-;@>n1;PQEP-x1V%`nxrQ6OW3iKB?n}?nP6M42%m>6kF)& zlOd8&kuB|hA=>M<6I^J5WW4P@I^(gqxw+J=tZ$&zhcSYONf4THu!|XdqHkSWkLsbD z4S9O@YAX`t@CHiGO{A4z<*<>_2H?hn=xL;=h0`s1UH8oG2M?IR+uoe3Wr9=i96B+X z%Of8&MUL}EzE}-o5qg8CMPV_>O#6}RvjXG<4Wt_Kfe`l#5gt@JckTuISw3&Sb3Ol8 zYiAzTfySeQFb_YrgOc{wmfxyC(4H5iWP$iGf)JGtbL*Vzql>`^EpwE zoL-Ce^X^@Hjj;m%4r%50Ayr&tH}%9i@gqxp@8-=GuZN7Sr&kF?)OOnc-0!RDmBk*0 z3>Jh+#7EvLF8<+gT)S@K9bO8|ar=1wQ*W5-)qO~{j^{_6@$!mY4DtdeOBoF-{Cx4> zn}@bl(vaCjWkHy|3rpJ#x4@?FAD$SVdaoSTQBYjFswI!#Gk%4 zi>u~R6B%L_0EP%u53+)(OA-*M*lHNDs~=m2w90@2*vh+%S*#@$JX;^tdhE1cv+Igx z%#ZMCZc66==SIFs2L+vxkDyQJgyWwF%`gd_e;hEnCGBNq_@wP(%}56Hhhj&ZHEVC5S-ZxE}%N4)7cyY5F-*xSo3kxf|7n)NI8!TK|WOW#gYMH3>Z4zwzL z`zb0Y+@c|N7+Rc)A#T0MxJu7I_4gQ@h6nleRMk<1CQ#YbQyb>4__c+>Fqx*1EsjJsh`jPfh}PXWqF} z&O2r`e)kwtO&y&#Au9uq1O*8rkr0Aox^TPDf8R5_>%sS}2JK~U0eGEmVfAx3Ut|ST z4qK6FrFi12->WjXI!sXdq0Rbb0l0+rbZ6*72H5}Y(F=-Vw!o@Wm*3RW`;)5@ou`&$ zNej7flV@WL`{FU`o$5sMcD|oJeZsaL>4^7ZH}9#A^y%59DJvVnRTX@hNS*LH>P{rw zk+H)F*n3d?-0Npu3>ngC2CNuF6XM8^=sdttJw_iftSk;2*9#tPl$5k3o{gPmGg%4> zzL?)syz=Yq(ejVBf$U%SkOLa5Gl}DMGJNQSy6-DIdDw2?| z*zgA2qTn%!*cC2YxG)QI;mq@w7G$?GOIPp#B6abZc4E|Fa8Q>J1`ZHSM|*qigh?^> ziD;tsVeqcujXAFU?6jHMcXFIiWxJx=GMWo1mdcH+tE+oPYSj=MKPZ&NXpEMGTn8G*)z7to7P!paq`6CY!w$?rDTV zPG)8~!=C-no@^UX?E@|C(m>0awaj42J($ZpI@zh;ggjsFCR;m-g}IHP-AA}(0^6R@ zZoq@{n3tvS&Bu=q*tz}3075JH3Zn<)y!v;4$m`$rHBl=qF+|9g@&X&r1o>b5;25I* z1!l*)@fR^4PCwswj#^Q(5Hu!?W22z-9huV_T}Ub8Qgz|O=Bf5pcdYwX4Rqbw0F=kJ zHf;;}7vE4_kwh}F@rz;b*4bgGS`P|Qp1yt+Fjy9qc|}2_F(v;D!#0wT%xhG`h{+L7 z$aNZM5dvHxQ3QYkBE&jQSZ;40d{2*Yx&M$$i?V@f}wU) zJat9i<@jS}=nu+>yf0$f;Jf$-HE6^!*Oc?uH|l00M9+ei(#~LvPQ{8`kST5ivT_Ijt&v?#al!HnO6jirR|N* zByLWM?YP%?WKu+)+Vyn@NfUB8at01+Bny)XE zT?6Fiq4O(+*sbvK;|h9rEb?w_8ONn)d%gD+6}LeWR`N;^ucHA{W+91&((R*9Vy-tW znKdFb5m|%Nq-)2H#z+9F-@W_7M+W@b_6O107y^ir2}J`ypMSyv(Aj?tbQa(27Crk) z&`9deXz@FeV4B0+j*q$G{!Ft(84`iQV*a+ODo~q_%3NBF$b~PSj2&+aZ3)ZxEZ-+{ zX`8$kbl51{D%e;@6X<%3i;A#bK^k8nak9*GDSV$_KT$dGy!%xvpSVgA#)JF!A)sfS z1a220y}aJQX#GP5M6W6lGDYb-Q7n*7rF{2MOjf+1suDP#Wx%*qZ}+{siH<&lg8!9| z)XpIgi~lZQN%-YAki*Fsj-Nk!W@Bi$okDotZhmw8myEpGM^i*7#pO$vPSLgUA1s)} zylzr<3a^)e0rCaIv0w%U2I>eLOH2CI&|p@Xag(^BaRO6PJp0Q+k9MEYX85pSb_u^h z^0dT2VG#7EYGSj7WO;n#G}|9c)qL*=*68}O383|4mboHBy5PZd!H@SE=NLqQlnn)} z-8+8P=<0;fhm3Mxn-aj!qP+~jYBC75r27exbe_*GrJm0O7fc*Ck zE$imBYL!~(#D?O}XUS>daru9RG6k$DxO2xONFi@_gtciO>&p4XQ|rwh1m=w$JvyY# z&TX)qi@d#4Dt|IUsYtJ(scrh~E9+|~BGhantiNFVQElL*MV)%Dc;3coZ_MH~YBTaS zQf|uIk6@P<&p~@8F^7;~Ne3b(D6h1jk)P#}vO;FYI+5p4eopR|jm6QylUAPi5*z-j zR2kiw6R%aYwXRWB-}{5XnXnUwZJuAUJHO7!t&iKw6XT8xb|mVFi)TIuCQ=k2<7 zRjE5ej$P~ii(gi41@xn85)iO`H3A=QNTXd=-oejZPTh=SQP{^z_Mn3CvGwkftw7oD9Uq%^8a|Q6REi^RL{1pUi zbkd)hphmqlwX_6ukGH6lHxXm^5D~-%j8RJI0^b&$s4zmpOYhBQN#8<0KtY_06owJZ z50F9R`2nd(+KSfnY_}m(5&$jtb=PkvftIx7O%SmO21PFFWB2Tx$4T)oqO|f^{##yIeFkfq!5}29T7(F3JVLH)$_j~5c4jRASh$qaclT;Yqw>~ zZa;fAbD={TEeG_Z2xkGvc5v_XjV7-%oS@zYT*sv!KI~(H-YO1Dus<28g^+iNRr)dJKKA{Ey+w!1rnKS4*kXbd!Tbc|QV z;bj%3OcAt4f4dvJR)pP&a05Cj-`I{m;nioOt5U+{@V>+~Hi9{ze zTDB~MIQ(t&vd=Yru{rF-xCC~-h3Zv<5mJTs_M>{88ACvKU?eFg%L;Sx7UIBV$`Ls#^SImr3cka}#vFJ6-L~LE$ zOr#!yZPC&)^ziQg8UAEwX-VYtynOts{ zp3c*wEj?ivg}m9%PkzXvr${?!IaGVfqP!6752LGfnfKBX6@|Xkz$;==0}YX$cj4(We{^x-j#S ziPAdNPK{vShM?xqQ^S~&w7ublWW)FF-J6`x4w;LCkS=cpr9?H2@uZ*3MLYzN?&ug@ z{Emii*B0%pw0h-A)rAlajc9c;>n84}i&2w!_m(bR+&34gc{D@9orlxg&%Ss6zP8k@ zd-ti4ico{2h(Gk&YA7G23M>s~szYMFyn&8MXydXoJ^~aseo85}n=)lLopFG1pEZg{ zCTAW%N{9^KxPfZOTp6SK=ajwPQg`?BSA00dVlv%u#|92+Fp|W@Xn$qAlr6pJe7msv z+<}Wu&(eK-%x3Sri2Y#Wo>{i$GWNSnnNHIyhdGQ%~82PxL8@blF266xXl3W$V~@a>TMDmE%w&MiE-pWwP!HWNE>#cWA%f zP%}`rl>JwyENU_?>j;hB zdi^!eaeucFv##A#}B~tkc^YcXmojhdcrthOXw}N{J8dDmDZ^0~Ng$fLa z{m{W?dp0*eUluU@PC1kWjgE_3kQq_TPOkG#pVdxWh?^v)_-iy07||Ka!NgWfA_vunsZ(^cq=d8M|oV$nI75isTND1U6xmh z(8;VN=NThR<9_^FT>^N^cP&M1%I&bEJCiMCj@8bd_&yc3aw_YYt@{#%rLj1@DGRTD zKF&9^LlJzO_MX${&s(HgVzo&I^$l<+OX8ln1X*y^4BM7;uX-KYBptudO|`x}H77RY z70t){nwqIN?NJW;^N@xBm({$kcH`tAUpN`K%G0z`!R9)20Rz1*@&+z|?wYc{+Zol} z5U%$qtQ1fO)j>i;Z3zGb6&3L>s+NkCR5sPsA$22-0#oW!$kle;M_TAKZ33uNl9v}F z>B*GMBp5mImooqKKkUQgEdI;lu+3*z-iIFP%3Yu&3&7&><3JwcVo1JIr%rX{@E59S zbdSFe9lD8rENA}*Gh8zb=$!K(K0Jv1N^s?@D*F#wIp{5isjK^=Q#7P>K88P}Unetd#r(75avl*26Qjz+-OGZX!ocGt$Mq7YoT9NLAHhRPrtD9H{ z8JAK~eYbAgjfCH+=p+wA16y~WU^;zt4)+8KKA&iRREpDo&;I+!k(FRC%ma~3%bdW~ z@T(?%6&#;cQq9r?~)H#@J_Ag#LQr6l`6i;~CvGj`h26-@X&_&beRaYz1|3+CJKLUZxKzXf_; zS~$B;PhjR*$KII)(~2Vw`3U$mh*%0VyyqRnPB*XbP+Z^l@-ep?0kREKY5E3d^~AtdFlX3^Hv*d?`L;uP7B z&`D*LmEQ_~fw+i&2Z|$P&N0d(A2f+3QJo(H+nbxmQz z#*(6b0|vO_&0*R<_jOv$ueZDyoh~ht!eQM|v^-?rHA{SY$Q7iSA;72e>by<;8#pp7ppqU;!52Pm4xBmjP7XMQ+ma>u%o!f7 zj`j8CWPr?X7WBnpV=5?cW>mJfbwCYwH~Lgb=sIqhz)f9UGXZXXUHYa#RxA6u1uuE9 z`}m^A0SeIUu@9msB{|FpY7&8geRD;smlU8hgys_QUnDv)?Y*td@Y$b~3Ky;Q4){l_ z!vcDCVYWV;{M=N3-41PloN7~kO%|;El(ey)8eMCJFIzO?ZyZ1Ss@% zzL}fbh9Ow5o?g_M!|mv=XMOAt=|<$XLoPEJYTrY|FcIK1tFzX!HWQUdz{2w?=vtw$ zqJGC0^%Bc1yjSEj6dt~y(Tq#ui+|k2@Olv~bVqN>p4;jYl=!j|Li?D3`bd?V=aL-8 zUYfz~>@j!eWEpw{*F}rAx$f_3_NgRIQKI*rF?+eQvy6yAww>KHVD-Cv8I(~Qs`vAN zOiW65hW-GvlO!RuimM>^^&$az9aEyB7Vpp24K|lZVL z5w%8(lyo*gxHu&BVZ+pr7V5pB*OQu7mRF;R$)rg^Y4!jk z>T2Sm)rr>RBnh&e9QLoB$kBe(c$i!jR@a%t<6kLj(iht+m2jAin`7#>Eu>O0!h^fv zDslWgsH&)p))KUu+UuW)hL`OxxaCymt&g*_cjMfRYy_8K!`GHLp5$O;BO#VL(qFT$ zSOgLEm7kHZ4e_W5hY}Zu&af zwXv(;8PJlE{pc7(20iAM2;idAfbbx5(1DMtHk2o$%B1I;0++|YkVwT9!pf`%2I5+h zY+iZmM}Md#a11A!kgVl)R;2q9vmq?UhnFdJ9cSwDvetcFa`9OOQ%foG2KJk6r%$^x zol3sU3^&?5W>0c$I#*aTqviaO|CJg4R$Zj1Eu`H7Rbe~NJZ%;@FDXQP_@K~M^&Hv- zDk75aMcxLNkzY`-6~>v9>UQx65TgHfIR4KC*hV)!KYeTTKTNofUfb{gY`gm`I{tSq zT=Tz^<%4=ug@SxRFOfzE|CfOt7PUmZ^Kpw7I>2;j4Q`_}jIh_M1?xz63v_L2&FNuE zgb|C-E;`{)a{gC!;te`nz-hvpad%~#Bzun{&X)AfKIX^8U;h?a7O3R;h# z8iW51cAO2#@pp$0e-bx$FNzcn`s?aL`Vkh3FOcLf>KL62{{H8n93H8mFfu5CFKz54Ei{Sg56^fNo12|D&{$%`=eA`ynOk5!2x74gcp&X927*KqTkn=GI0cl<*FADMCxnk6d*y-xD4spfQZ=6d5rX!iB_+_%XcM3FD9t z;^PtdNs>C5Jk*{g#c`oWN0aN+gE>PSvMG8Qa^0|LEm>-|+gTh3lay3&#bdU}*9Kz~ zif-_~6{t`CrS>zOI#p+il_!n_7g<*sQ!*LHjNMfH8w|K@?^`& zV7y#`I69d`t=F&TUuYKq5S&GdoXESoy!=%+nh@-P4jT`!>cp8O>i+C1kw7?T!ZN{N zm6esPmzhskgD6Y0Uq1y&?1mU3kpG(mtg6phmi6LAcSif*cR9Jalaa!pn?n34juyr2 z+zUecU13b%(~~eDDAu-X%eH7icGOgxDRfj@n*Xe0uI+%(5PDsB?*W^{v7?+pptyx{43IhC{!E|N z)!*`d2U<1*68Mob~EstKkWBi&W{iG^Y6 z>P-;UayP+q{cv#)-2yewOBD1Dd*2(n2!{{iz&=P1?KLtNq44iNeAu}LM{0=J1I0}7%whzTqA4M4?c7=LhtVS@*M2}!(HxRVtR$+Yg%eX2HQ-NA7C0K_0o z0Xtb>V)kPOv#_-6W5(Wh6vB;OJgCtR0f(m4s%1+Y9b0)Raa4^$&nE8+JkzaGjF=R~P@seUu2`i z9wv0vX!8~VHmIHTo~1AIg@6OqdilKB#214ciDXSq!ZWM=arx@iD1=!eOoZOwui_!u z^gU*5t9z24FBa8$iY*-5(2*mL(2{}bEtoUs#Cpp$c^mPL%89&{uWWt@i{G-O-+lZz zO=?7VWEMb!?*hdqlaH2%bih>Veon0aeg;VZsRnNI5TpP&W?Y_U;2a;nZenx1wP(m` zw2MpFWK%8?zkTzjfQFWS@nPuWVSW2fv8d{!em{;^UEUY1 zo$@{E@KR!`SjU0dQ!qq>vzqk`fb8nn(}=@Qa$=QCk?HDqE@Ees;n>xP$oovG^n2sh zeLAt{0lKb85GdETFOf9KmNEnzp?eA}EIDfWm9f8%lov8=N{~W>X*zW*_*aG+^5!6; zzs4=xxnqZEB`Y}SrK_9ayQ*rd6_xWBh>YV%cQl!DHxYo(Fn$O)W+DkYo!Ru!8(0O* z-Hr=wwVq;ZpB4bqD|eHVOC|?#tYjEyswil=YCO13ROV+K5?1SPlx&H7zF*ht;FcXe zLM{gxks;Jx<_pDCyLn}awEpe=u4b>;FJktk^bP$1js;(5H)izcm~s6Or1?qO#Z$Iy zx$)E99)CE&sQ9K%Kbk>&tJ}wAx`lh|2n*2Z*rug8e3oN}dhsXbZ)wm01B^z#cBNuo z2j_6B&@m1k-e}?!3{EUm#F@2EBJ9P~;F!}GkYRE(2;VqlE+ki;$0o@?IM$W?JTW~A-> z6(vP4CjaB-6QHAMB{YMaIA7tMhv6E2CM2ZaVNgCYy#qlWA_r(|?~uB5?|v?_@4$i6 zPSghYyy_5kKSWPG^=*t*)gM5XCmSp^s%nDAnd^O#q)uzij3(LlpJCecCUs}=3RxDd zoB@xuV^1xUed>~zruHaL+PS1EG9<<`(`WU)du(#cupZesm`j-lv^Sf_t}EdS3n38? zdscTLH5vQ1xEkvXeukl1DfK$CUlcNji-9^@R?u-kwb_%CI56h4k4OC8r)pLnK z;+%pC?JOVoo?dJN!ca%-h(dt)1=yk9A}!Tl zZ-9~9^ld=9{N9Y1q>4&bhyt#A-y^FPJqLYT&|OxElc#6=^eA}bT+PIbUA~_V-FD(( zmymF7U!);!T=3n18y$X~CA8hGb5{VCr-NVwC8>4m)=5>2g)Wl8W{sy;@hnn_4bP5l|*bgzx8V=a_ z{PTJcW)x**jNon_ownS5e#hM~!ZPnSEvM+L`G;}#z=qXL z_RLukRIS{KXZ4Ze+-w(&hf2$7<^WmU>NF&+*rK!E?XBJb4&m0;6EI2E?9h$_2Q2s3 zSDUAA`6JSvg^dPaEfdwTh$5iH6i38S9*m%Uk%qS5oe(CN@&xYt`ilMf0KW3fsc1c% z!0Slm9!89aaC4aFjUZ)BpJ#59m?H+u(5~b02oU5RrFeae>CSX>fhZ&JX&wfE_^!kBr13 z(K#t)TzQ-k$yw<2bZJBo+W4MHjBl60edHp!=c<0HkD z_i)%VVdJ6ZsL}3p8Ma7Cgs>BR*qUSKrWd@pzRnX5)I^6UKsowzLWs|nJBhOUeQ}6dgH(rik4#D6)G%HSwZN`0zTtH+3|!33ZB6*P(J;i->|38FUKE z)NF4%gpGy^apHUp5f1}iEU-37__ZB=WwFFbX~se!&%Hba$jmb7V;VbZE1$z9#O#Rs z6JNnOBoJ!OJT7|Sq$eFSirw0TZSLxv#E>LO1ZV)DJ-OcWJoNo=~Fuii{3@^u4Y~)b6@PUFf?pI zr=#bS@oHvI3=NE@B1*x2OD0<@2c5J4hCDoO5y1drcs6D_boVO+k8lKzPn(kW1 zD-m=>)JtCA_$RkSQ%&MW1~#u{9)a-54EPrjC$E>`7kNy^eDK|wW+hp@fmIFMT zf#!AWaeQQJ5RYyPKCyAOl)8X&?AbmMjg5E;#mngq@o|W`oP1pS(NhqVFw?U-t#=>! z^SSn=A`?k)`L-#Jjz_!H%$_r6z+XKWG0xAMU#N(>>VQP$cl2^bJu<~*-0J$G54^~G zB9=^EZH|ywn8~7Tv~nV!qkNhqk^76TS|KO4WfzSDYwsS?aCt>(6ZSC9AD+_#%C(XK zRKb^W(xIm5+hZ%G_U)@!-C;4C380=*{nxN{=}m59vTak2D zWF#joWLBZDmp8+JF6C?x8vW%YFg%)$4p>(CcK4igO>2^_iIBd>*6GDQ8t}8>+Fy=B zcPn-2(E~KX!pqrFUajY_Mf)mesYLql)5bkBw!IOlzuy!ilB_i6?9DiOu9pXIt>#JE z&fPeW)TFI%hAT=hhxcW=$gPy@i>XN_H6}l7cTSQF;AL z4pxDX7V<>kj(vxgE-9RPIfvhQ_vVdpxZcP@nr)gtP3w*pVWFXaZ1>^Cai$MYu=luM z3(BnjfrH)s4$Crhx_rAC*gJPtqO1SAcRPcH!E>*(5qD$tx^+>^FkSjMzM6E{q4%3d z#l=yG^IyGuxrBCpSG_{**~&|vk5mwN3c^U{OWKc;z@WBWhZ^;GX{BkjNB(;ol_6ll z6|+6lj3w2+S_1D+7!;0GySqF`8C(f?Fc4K=VBrPMKfZ3Z7`-`^Z^YTNZ|y#w^B1`V zsXt+b%%&SJm3LlcHLpK%ahQn61F-D>QjQND8VLyYZar>=e;9TICzLQt2~ofq^mFT1 z`9K#vW!FVkYgS&xzT5xGSfpM-gB&mVvbuySfwr{Eqw~mRL6D16;^&Vj3ccFL*V~|| z!l>RjHHzbuMIw#}p~O*v`o##vqq2(1R-LIwAYDsC){Jk@bT7_n7sqAM-UJ;vl2KgT znXh&myLskF@HRuFfu1)S`iOc}P{3(}&_LlRc=2FuXI2&gj=aAV0O4q(5fq0Up=;ZU zXnoe1@l5i!4`~=WEnj|soC%<*R;VLx(fAecRwtaqdWcgDHP)<}??0>S>DlwiYaxBc zHc{Q3d=1ur?Hc1XgpSBCnDWU66m|4r88GA*Ni0OcdyB>rPs5?qPBO72`+0IM_m2({ zXYS5AzTx`^e-wqcA(FT-vGoy%i4>+)aQ19CR7&M3ECvC_xj5ZifKNav<;(LqZPIpw0B@t=KUC6{KT=WL0Ma*#|mdU85~&i;E7l z#{kQ2mT~v4JPx6s93>#sl0rh6pRdgCh+J~ftnWiY{boIsfn2Mm^zWba&&JfWZ}HPG z;&S=TS^lMNrn^QN*eEDO>P8-VV0?8zbcj>rDz`rVHdkFeEqXrIaUXK{eR){s!d=r= zzf&A>eAvAse-zXLj_F-AIPb2epFh(*+TCG?&F?>HrN!N^y^yUq_@TVc%=GT)A0;P8 zR?c4eDWz&=tH7KcDBOfo7Rb~D*leGP*1Qexb>6&0N+{4xP}D`2x=I&avf8jBZ@VO@ z_wPTo;kqM;$-FHM3&lN{5Y}FtM#ajiwJ}qZ)YxeK2 zNVKEUyH#UC|CRkgJWTMAZe@2@Tz_>GHVB5|3oOq5`W1I{_=Dq3T5Xr1UzozN-mI;l z?{ok{!6~47(E72vw6q6yTN}_$rL9neam-fFw|Sv^(R_&D){)2Ca`+kp!li(bEd4%3 z=KGt3ET{6e#qb*m>($1$;xPy?7m%@Z#i)FQ_Cg?vK*cd_LsDYXc#aY)HG8^MY0{z%Q?aEBF8K^UZBOY-}laG%5kNkRV#FbQI8$8CG=6ngtF~^Ca(|eS+`(;*0^5n zL7E*RVnOtYKe>b7P$s^3ub*Fmw`}^gYu!YmER&3gz+xIuTzj3vz>cl^u_5gzL=Y|j zxwLr)d29;+uw@opdhyX*){0UiPHW?M4_}XIHPzMDTsOcGtcy7DBlk&Ai=|7J_&%(9 z{B3QJ(YM!M<8OCCg`^=>V(e-695Ky9MF~%B@2wxRTQqE%Ff++5*v)R^xgtI0!l6hI zd@DFPWdJy)ZO<^K_;$MuNB{M72zCwS!zI(+!hl?;K8R(v+Y06T^hPaxQR3yIldWWi zKf)>OUe{k~{U}o|NFMn?J5<=cBvbm8{4GA;o;aOKZ`zM~Sw@|fJb-=ED`n0~AWR*N z)1I}+JO5t#_^cWJS{9?h3Ck#s6Q2qj9lUj4MaINRAptsg@Ne?KV&dX@t$0bDzZUSl%$HtC zkmYB&kDQ86&|vZ+!EA6U}lk_uB^lq3>- zC0B@4^WziGR@1|nzd))Hll!~w(ldAS4^IsUnj9o)YiLX=L7>#YoqogqZ&w~tvZ3a} zq|L32zEyTRtTfeUk&~@$fDkagTK+dU(w=ATM;4#-Hj(aUd8x?_QGTy9=z}^4a;y$mO4D+&W zQg1@}LPA0&J&d_MB2eZ`@drM=+j+IfbT=Q+icu8(t^f%9j^e)RGN-CEr7X&W6oAsiqj^j`j zacuBLwp()bnLA0^hG46A>lE9x!S7?}un{u(?yAQ4$1h)=ul~)-&Mzs6Yy5GcxaRPo zL%!TyKT`we)*I60!JnNH9Di*NYsz>I=k#U5A8{a*B-8J6b0rlHLHteEp`6#_SmcA2 zUMj7qH5$Ie@cGedrd=`H!KjqhZ)oxB23jHf?%hEtU781-e|&4n@YpS@ujL!gLiS2< zw#~eGan)lvFff+T6A?E^(8Y<^_{2n2N%riR#`!%ckut@SFI;F$T*0G9+sF<-`d|?Z z>CPTk3zqCCa?1k93{I-tGA~|mJG(8T3>j|kE@N>#KD6BN#+M95S%VUv=FJPuUIAz6 zV7u98ateFp!Jn>aes{57%lVSVXbzqSCVmgamNsBUZ1*G7hi@Cw90zp5h!^{4-rTtZ zxrSgi&II0x-^{E7B%y9DUp?jwLFY`qu8{VTkKb1^Q069BM%mGRXiBaqIa?ffkv?)W z)8(V*&-FAlvC<^6JISa6B=qt>xZCeeg33$}ZkQ%Mp39Q*rDp@!T9u`t&KYtIFi9qh zD<94NLbYwt>qx=-)wz$-3H$P`V5HI>GiKK6F`-mQQ(in?cK?DULG0F%heYH>63HU^F{hwjjs=q4w1s# za;}P@QQ-_;t@Dygvs>Wv=d;$Q&0~*f4P0q%@ODXTeEjZL%Ug?68pDztuUiv=hE8s)@TCJAIQ8*(_peWz~4@?O?#1x zjnyKk>DHHqO(Kvo_S`v<{w!EyMtDxF>~g2?BqOUmH)Jx8nIB}Rc+GR#ipLwQVsQ9p ze$gYUx~NBq$bHJN=pXcQATX zzIjuYQgyO>O@xZd{%#LMt1v!i_}HpxMn-A>y-oN}9mD_XFLg7T@6pQKS=qzLXgF=h pnZ~%&*=j0>*RFWJgKnj%^@D{DQN3SHR+RXknX#o&++?S1{{bzAGspk{ literal 0 HcmV?d00001 From 67ae181fe4b0b4ca8ab84b2806903793c6fd4dbb Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 6 May 2016 12:49:37 +0200 Subject: [PATCH 31/33] Require sphinx>=1.4 (to avoid latex errors on readthedocs). --- doc/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/requirements.txt b/doc/requirements.txt index 0b7e3f611..892fa8f44 100644 --- a/doc/requirements.txt +++ b/doc/requirements.txt @@ -1,2 +1,3 @@ +sphinx>=1.4 nbsphinx ipykernel \ No newline at end of file From 21a5aa29dbbbce864f650db1913ddde3f7b67f22 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 6 May 2016 13:07:23 +0200 Subject: [PATCH 32/33] Disable latex/pdf build on readthedocs. --- readthedocs.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/readthedocs.yml b/readthedocs.yml index 361e102a0..763fc6dd8 100644 --- a/readthedocs.yml +++ b/readthedocs.yml @@ -1,4 +1,6 @@ requirements_file: doc/requirements.txt python: setup_py_install: true - version: 3 \ No newline at end of file + version: 3 +formats: + - none \ No newline at end of file From a1e1e8add2e0aef6429e023d575ae8afcac49546 Mon Sep 17 00:00:00 2001 From: Lukas Prediger Date: Fri, 6 May 2016 13:12:12 +0200 Subject: [PATCH 33/33] Fixed plots and references in documentation. --- doc/source/concepts/sequencing.rst | 2 +- doc/source/examples/00SimpleTablePulse.ipynb | 2347 ++++++++++++- doc/source/examples/01SequencePulse.ipynb | 791 ++++- doc/source/examples/02FunctionPulse.ipynb | 1567 ++++++++- doc/source/examples/03Serialization.ipynb | 797 ++++- doc/source/examples/04Sequencing.ipynb | 793 ++++- doc/source/examples/05Parameters.ipynb | 780 ++++- .../examples/06ConditionalExecution.ipynb | 19 +- doc/source/examples/08RealWorldCase.ipynb | 3117 ++++++++++++++++- .../09DetailedSequencingWalkthrough.ipynb | 32 +- .../examples/TablePulseTemplate_example.rst | 101 - 11 files changed, 10032 insertions(+), 314 deletions(-) delete mode 100644 doc/source/examples/TablePulseTemplate_example.rst diff --git a/doc/source/concepts/sequencing.rst b/doc/source/concepts/sequencing.rst index 51670312b..c159101f2 100644 --- a/doc/source/concepts/sequencing.rst +++ b/doc/source/concepts/sequencing.rst @@ -16,7 +16,7 @@ The sequencing process can be interrupted at any point, e.g., if some parameter Sequencing of Conditional Branching ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware will then never know of potential other execution paths). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the disadvantage of being not real-time capable (cf. :ref:`Read more on conditional branching `.). +Software and hardware conditions result in different instruction sequences generated by the sequencing process: Hardware conditions will produce instructions for all possible branches with branching instructions corresponding to the triggers specified by the :class:`.HardwareCondition` instance. The selection of the correct branch is then made by the hardware. Contrary, software conditions will only produce instructions for the branch selected by the condition (the hardware will then never know of potential other execution paths). In this case, no branching instructions will be used. This enables usage of branching even on hardware that does not support jumps with the disadvantage of being not real-time capable (cf. :ref:`conditional branching `.). Implementation Details and Algorithm Walkthrough ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/source/examples/00SimpleTablePulse.ipynb b/doc/source/examples/00SimpleTablePulse.ipynb index 71c4f18f5..0c0857efe 100644 --- a/doc/source/examples/00SimpleTablePulse.ipynb +++ b/doc/source/examples/00SimpleTablePulse.ipynb @@ -15,7 +15,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": { "collapsed": false }, @@ -58,24 +58,782 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 3, "metadata": { "collapsed": false }, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", - " \"matplotlib is currently using a non-GUI backend, \"\n" - ] + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('

');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "image/png": "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\n", + "text/html": [ + "" + ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -175,7 +1694,7 @@ } ], "source": [ - "%matplotlib inline\n", + "%matplotlib notebook\n", "parameters = {'ta': 2,\n", " 'va': 2,\n", " 'tb': 4,\n", @@ -193,24 +1712,782 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", - " \"matplotlib is currently using a non-GUI backend, \"\n" - ] + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "image/png": "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\n", + "text/html": [ + "" + ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -127,7 +885,7 @@ } ], "source": [ - "%matplotlib inline\n", + "%matplotlib notebook\n", "from qctoolkit.pulses import plot\n", "\n", "parameters = {'ta': 2,\n", @@ -139,15 +897,6 @@ " 'tend': 6}\n", "plot(sequence, parameters, sample_rate=100)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { @@ -166,7 +915,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/doc/source/examples/02FunctionPulse.ipynb b/doc/source/examples/02FunctionPulse.ipynb index 5bb99a684..0b9e8b38c 100644 --- a/doc/source/examples/02FunctionPulse.ipynb +++ b/doc/source/examples/02FunctionPulse.ipynb @@ -13,24 +13,782 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 1, "metadata": { "collapsed": false }, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", - " \"matplotlib is currently using a non-GUI backend, \"\n" - ] + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "image/png": "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\n", + "text/html": [ + "" + ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -87,20 +1603,11 @@ "source": [ "param_template = FunctionPulseTemplate('exp(-t/lambda)*sin(phi*t)', 'duration')\n", "\n", - "%matplotlib inline\n", + "%matplotlib notebook\n", "from qctoolkit.pulses import plot\n", "\n", "plot(param_template, {'lambda': 4, 'phi': 8, 'duration': 4*3.1415}, sample_rate=100)" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { @@ -119,7 +1626,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/doc/source/examples/03Serialization.ipynb b/doc/source/examples/03Serialization.ipynb index 6514f5495..95490399d 100644 --- a/doc/source/examples/03Serialization.ipynb +++ b/doc/source/examples/03Serialization.ipynb @@ -38,7 +38,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Assuming that we, again, have the `TablePulseTemplate` from [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb) we instantiate a `Serializer` object to store it. `Serializer` requires a `StorageBackend` instance which represents the actual data storage. We provide a `FilesystemBackend` instance which will store data in the directory `./serialized_pulses`. With this setup, storing the pulse template simply means invoking the `serialize` method of the `Serializer` instance and passing in our template. This will store a JSON representation of the object in the specified storage. Since we have not provided any file name, `Serializer` chooses the file name as [`main`](serialized_pulses/main).\n", + "Assuming that we, again, have the `TablePulseTemplate` from [Modelling a Simple TablePulseTemplate](00SimpleTablePulse.ipynb) we instantiate a `Serializer` object to store it. `Serializer` requires a `StorageBackend` instance which represents the actual data storage. We provide a `FilesystemBackend` instance which will store data in the directory `./serialized_pulses`. With this setup, storing the pulse template simply means invoking the `serialize` method of the `Serializer` instance and passing in our template. This will store a JSON representation of the object in the specified storage. Since we have not provided any file name, `Serializer` chooses the file name as `main`.\n", "\n", "To specify a name, we can provide an identifier as an argument to the constructor of any pulse template:" ] @@ -63,11 +63,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "This will create a file named [`table_template`](serialized_pulses/table_template) with the same contents as above.\n", + "This will create a file named `table_template` with the same contents as above.\n", "\n", "### Loading\n", "\n", - "To load a previously stored pulse template, we use the method `Serializer.deserialize` with the file name. The following code will load a very simple table pulse template which ramps from 0 to 20 over a duration of 4 units of time and which is stored under the name [`stored_template`](serialized_pulses/stored_template):" + "To load a previously stored pulse template, we use the method `Serializer.deserialize` with the file name. The following code will load a very simple table pulse template which ramps from 0 to 20 over a duration of 4 units of time and which is stored under the name `stored_template`:" ] }, { @@ -78,18 +78,776 @@ }, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", - " \"matplotlib is currently using a non-GUI backend, \"\n" - ] + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "image/png": "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\nwlKnmzeDeQAAAABJRU5ErkJggg==\n", + "text/html": [ + "" + ], "text/plain": [ - "" + "" ] }, "metadata": {}, @@ -38,7 +796,7 @@ } ], "source": [ - "%matplotlib inline\n", + "%matplotlib notebook\n", "from qctoolkit.pulses import TablePulseTemplate, FunctionPulseTemplate, SequencePulseTemplate, plot\n", "\n", "table_template = TablePulseTemplate()\n", @@ -78,7 +836,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 2, "metadata": { "collapsed": false }, @@ -87,7 +845,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "[, , ]\n" + "[, , ]\n" ] } ], @@ -126,15 +884,6 @@ "The latter two will only be generated when hardware-based conditional branching is used in `LoopPulseTemplate` and `BranchPulseTemplate`. This was the main motivator for the usage of such an instruction sequence rather than just compling one large waveform.\n", "Using only the `PulseTemplate`s discussed so far, only `EXECInstruction`s and a final `STOPInstruction` will be output by the `Sequencer`." ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [] } ], "metadata": { @@ -153,7 +902,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.4.3" + "version": "3.4.4" } }, "nbformat": 4, diff --git a/doc/source/examples/05Parameters.ipynb b/doc/source/examples/05Parameters.ipynb index 9e720db03..ad59f99ba 100644 --- a/doc/source/examples/05Parameters.ipynb +++ b/doc/source/examples/05Parameters.ipynb @@ -21,18 +21,776 @@ }, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", - " \"matplotlib is currently using a non-GUI backend, \"\n" - ] + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" }, { "data": { - "image/png": "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\nCBMaRcHF9AAAAABJRU5ErkJggg==\n", + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('');\n", + " button.click(method_name, toolbar_event);\n", + " button.mouseover(tooltip, toolbar_mouse_event);\n", + " nav_element.append(button);\n", + " }\n", + "\n", + " // Add the status bar.\n", + " var status_bar = $('');\n", + " nav_element.append(status_bar);\n", + " this.message = status_bar[0];\n", + "\n", + " // Add the close button to the window.\n", + " var buttongrp = $('
');\n", + " var button = $('');\n", + " button.click(function (evt) { fig.handle_close(fig, {}); } );\n", + " button.mouseover('Stop Interaction', toolbar_mouse_event);\n", + " buttongrp.append(button);\n", + " var titlebar = this.root.find($('.ui-dialog-titlebar'));\n", + " titlebar.prepend(buttongrp);\n", + "}\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(el){\n", + " var fig = this\n", + " el.on(\"remove\", function(){\n", + "\tfig.close_ws(fig, {});\n", + " });\n", + "}\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(el){\n", + " // this is important to make the div 'focusable\n", + " el.attr('tabindex', 0)\n", + " // reach out to IPython and tell the keyboard manager to turn it's self\n", + " // off when our div gets focus\n", + "\n", + " // location in version 3\n", + " if (IPython.notebook.keyboard_manager) {\n", + " IPython.notebook.keyboard_manager.register_events(el);\n", + " }\n", + " else {\n", + " // location in version 2\n", + " IPython.keyboard_manager.register_events(el);\n", + " }\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._key_event_extra = function(event, name) {\n", + " var manager = IPython.notebook.keyboard_manager;\n", + " if (!manager)\n", + " manager = IPython.keyboard_manager;\n", + "\n", + " // Check for shift+enter\n", + " if (event.shiftKey && event.which == 13) {\n", + " this.canvas_div.blur();\n", + " event.shiftKey = false;\n", + " // Send a \"J\" for go to next cell\n", + " event.which = 74;\n", + " event.keyCode = 74;\n", + " manager.command_mode();\n", + " manager.handle_keydown(event);\n", + " }\n", + "}\n", + "\n", + "mpl.figure.prototype.handle_save = function(fig, msg) {\n", + " fig.ondownload(fig, null);\n", + "}\n", + "\n", + "\n", + "mpl.find_output_cell = function(html_output) {\n", + " // Return the cell and output element which can be found *uniquely* in the notebook.\n", + " // Note - this is a bit hacky, but it is done because the \"notebook_saving.Notebook\"\n", + " // IPython event is triggered only after the cells have been serialised, which for\n", + " // our purposes (turning an active figure into a static one), is too late.\n", + " var cells = IPython.notebook.get_cells();\n", + " var ncells = cells.length;\n", + " for (var i=0; i= 3 moved mimebundle to data attribute of output\n", + " data = data.data;\n", + " }\n", + " if (data['text/html'] == html_output) {\n", + " return [cell, data, j];\n", + " }\n", + " }\n", + " }\n", + " }\n", + "}\n", + "\n", + "// Register the function which deals with the matplotlib target/channel.\n", + "// The kernel may be null if the page has been refreshed.\n", + "if (IPython.notebook.kernel != null) {\n", + " IPython.notebook.kernel.comm_manager.register_target('matplotlib', mpl.mpl_figure_comm);\n", + "}\n" + ], "text/plain": [ - "" + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ], + "text/plain": [ + "" ] }, "metadata": {}, @@ -185,7 +2475,7 @@ "random.seed('Some seed such that numbers generated are predictable')\n", "parameters = {parameter_name: random.random() * 10 - 5 for parameter_name in all_epsilons}\n", "\n", - "%matplotlib inline\n", + "%matplotlib notebook\n", "from qctoolkit.pulses import plot\n", "plot(gates[0], parameters)\n", "plot(gates[1], parameters)\n", @@ -201,7 +2491,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 5, "metadata": { "collapsed": true }, @@ -231,7 +2521,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 6, "metadata": { "collapsed": false }, @@ -267,7 +2557,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 7, "metadata": { "collapsed": false }, @@ -310,24 +2600,782 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [ { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Anaconda3\\lib\\site-packages\\matplotlib\\figure.py:387: UserWarning: matplotlib is currently using a non-GUI backend, so cannot show the figure\n", - " \"matplotlib is currently using a non-GUI backend, \"\n" - ] + "data": { + "application/javascript": [ + "/* Put everything inside the global mpl namespace */\n", + "window.mpl = {};\n", + "\n", + "mpl.get_websocket_type = function() {\n", + " if (typeof(WebSocket) !== 'undefined') {\n", + " return WebSocket;\n", + " } else if (typeof(MozWebSocket) !== 'undefined') {\n", + " return MozWebSocket;\n", + " } else {\n", + " alert('Your browser does not have WebSocket support.' +\n", + " 'Please try Chrome, Safari or Firefox ≥ 6. ' +\n", + " 'Firefox 4 and 5 are also supported but you ' +\n", + " 'have to enable WebSockets in about:config.');\n", + " };\n", + "}\n", + "\n", + "mpl.figure = function(figure_id, websocket, ondownload, parent_element) {\n", + " this.id = figure_id;\n", + "\n", + " this.ws = websocket;\n", + "\n", + " this.supports_binary = (this.ws.binaryType != undefined);\n", + "\n", + " if (!this.supports_binary) {\n", + " var warnings = document.getElementById(\"mpl-warnings\");\n", + " if (warnings) {\n", + " warnings.style.display = 'block';\n", + " warnings.textContent = (\n", + " \"This browser does not support binary websocket messages. \" +\n", + " \"Performance may be slow.\");\n", + " }\n", + " }\n", + "\n", + " this.imageObj = new Image();\n", + "\n", + " this.context = undefined;\n", + " this.message = undefined;\n", + " this.canvas = undefined;\n", + " this.rubberband_canvas = undefined;\n", + " this.rubberband_context = undefined;\n", + " this.format_dropdown = undefined;\n", + "\n", + " this.image_mode = 'full';\n", + "\n", + " this.root = $('
');\n", + " this._root_extra_style(this.root)\n", + " this.root.attr('style', 'display: inline-block');\n", + "\n", + " $(parent_element).append(this.root);\n", + "\n", + " this._init_header(this);\n", + " this._init_canvas(this);\n", + " this._init_toolbar(this);\n", + "\n", + " var fig = this;\n", + "\n", + " this.waiting = false;\n", + "\n", + " this.ws.onopen = function () {\n", + " fig.send_message(\"supports_binary\", {value: fig.supports_binary});\n", + " fig.send_message(\"send_image_mode\", {});\n", + " fig.send_message(\"refresh\", {});\n", + " }\n", + "\n", + " this.imageObj.onload = function() {\n", + " if (fig.image_mode == 'full') {\n", + " // Full images could contain transparency (where diff images\n", + " // almost always do), so we need to clear the canvas so that\n", + " // there is no ghosting.\n", + " fig.context.clearRect(0, 0, fig.canvas.width, fig.canvas.height);\n", + " }\n", + " fig.context.drawImage(fig.imageObj, 0, 0);\n", + " };\n", + "\n", + " this.imageObj.onunload = function() {\n", + " this.ws.close();\n", + " }\n", + "\n", + " this.ws.onmessage = this._make_on_message_function(this);\n", + "\n", + " this.ondownload = ondownload;\n", + "}\n", + "\n", + "mpl.figure.prototype._init_header = function() {\n", + " var titlebar = $(\n", + " '
');\n", + " var titletext = $(\n", + " '
');\n", + " titlebar.append(titletext)\n", + " this.root.append(titlebar);\n", + " this.header = titletext[0];\n", + "}\n", + "\n", + "\n", + "\n", + "mpl.figure.prototype._canvas_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "\n", + "mpl.figure.prototype._root_extra_style = function(canvas_div) {\n", + "\n", + "}\n", + "\n", + "mpl.figure.prototype._init_canvas = function() {\n", + " var fig = this;\n", + "\n", + " var canvas_div = $('
');\n", + "\n", + " canvas_div.attr('style', 'position: relative; clear: both; outline: 0');\n", + "\n", + " function canvas_keyboard_event(event) {\n", + " return fig.key_event(event, event['data']);\n", + " }\n", + "\n", + " canvas_div.keydown('key_press', canvas_keyboard_event);\n", + " canvas_div.keyup('key_release', canvas_keyboard_event);\n", + " this.canvas_div = canvas_div\n", + " this._canvas_extra_style(canvas_div)\n", + " this.root.append(canvas_div);\n", + "\n", + " var canvas = $('');\n", + " canvas.addClass('mpl-canvas');\n", + " canvas.attr('style', \"left: 0; top: 0; z-index: 0; outline: 0\")\n", + "\n", + " this.canvas = canvas[0];\n", + " this.context = canvas[0].getContext(\"2d\");\n", + "\n", + " var rubberband = $('');\n", + " rubberband.attr('style', \"position: absolute; left: 0; top: 0; z-index: 1;\")\n", + "\n", + " var pass_mouse_events = true;\n", + "\n", + " canvas_div.resizable({\n", + " start: function(event, ui) {\n", + " pass_mouse_events = false;\n", + " },\n", + " resize: function(event, ui) {\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " stop: function(event, ui) {\n", + " pass_mouse_events = true;\n", + " fig.request_resize(ui.size.width, ui.size.height);\n", + " },\n", + " });\n", + "\n", + " function mouse_event_fn(event) {\n", + " if (pass_mouse_events)\n", + " return fig.mouse_event(event, event['data']);\n", + " }\n", + "\n", + " rubberband.mousedown('button_press', mouse_event_fn);\n", + " rubberband.mouseup('button_release', mouse_event_fn);\n", + " // Throttle sequential mouse events to 1 every 20ms.\n", + " rubberband.mousemove('motion_notify', mouse_event_fn);\n", + "\n", + " rubberband.mouseenter('figure_enter', mouse_event_fn);\n", + " rubberband.mouseleave('figure_leave', mouse_event_fn);\n", + "\n", + " canvas_div.on(\"wheel\", function (event) {\n", + " event = event.originalEvent;\n", + " event['data'] = 'scroll'\n", + " if (event.deltaY < 0) {\n", + " event.step = 1;\n", + " } else {\n", + " event.step = -1;\n", + " }\n", + " mouse_event_fn(event);\n", + " });\n", + "\n", + " canvas_div.append(canvas);\n", + " canvas_div.append(rubberband);\n", + "\n", + " this.rubberband = rubberband;\n", + " this.rubberband_canvas = rubberband[0];\n", + " this.rubberband_context = rubberband[0].getContext(\"2d\");\n", + " this.rubberband_context.strokeStyle = \"#000000\";\n", + "\n", + " this._resize_canvas = function(width, height) {\n", + " // Keep the size of the canvas, canvas container, and rubber band\n", + " // canvas in synch.\n", + " canvas_div.css('width', width)\n", + " canvas_div.css('height', height)\n", + "\n", + " canvas.attr('width', width);\n", + " canvas.attr('height', height);\n", + "\n", + " rubberband.attr('width', width);\n", + " rubberband.attr('height', height);\n", + " }\n", + "\n", + " // Set the figure to an initial 600x600px, this will subsequently be updated\n", + " // upon first draw.\n", + " this._resize_canvas(600, 600);\n", + "\n", + " // Disable right mouse context menu.\n", + " $(this.rubberband_canvas).bind(\"contextmenu\",function(e){\n", + " return false;\n", + " });\n", + "\n", + " function set_focus () {\n", + " canvas.focus();\n", + " canvas_div.focus();\n", + " }\n", + "\n", + " window.setTimeout(set_focus, 100);\n", + "}\n", + "\n", + "mpl.figure.prototype._init_toolbar = function() {\n", + " var fig = this;\n", + "\n", + " var nav_element = $('
')\n", + " nav_element.attr('style', 'width: 100%');\n", + " this.root.append(nav_element);\n", + "\n", + " // Define a callback function for later on.\n", + " function toolbar_event(event) {\n", + " return fig.toolbar_button_onclick(event['data']);\n", + " }\n", + " function toolbar_mouse_event(event) {\n", + " return fig.toolbar_button_onmouseover(event['data']);\n", + " }\n", + "\n", + " for(var toolbar_ind in mpl.toolbar_items) {\n", + " var name = mpl.toolbar_items[toolbar_ind][0];\n", + " var tooltip = mpl.toolbar_items[toolbar_ind][1];\n", + " var image = mpl.toolbar_items[toolbar_ind][2];\n", + " var method_name = mpl.toolbar_items[toolbar_ind][3];\n", + "\n", + " if (!name) {\n", + " // put a spacer in here.\n", + " continue;\n", + " }\n", + " var button = $('