Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The backend for TaborAWGs requires packages that can be found [here](https://git
The data acquisition backend for AlazarTech cards needs a package that unfortunately is not open source (yet). If you need it or have questions contact <simon.humpohl@rwth-aachen.de>.

## Documentation
You can find documentation on how to use this library on [readthedocs](https://qupulse.readthedocs.io/en/latest/) and [IPython notebooks with examples in this repo](doc/source/examples). You can build it locally with `hatch run docs:html`.
You can find documentation on how to use this library on [readthedocs](https://qupulse.readthedocs.io/en/latest/) and [IPython notebooks with examples in this repo](doc/source/examples). You can build it locally with `hatch run docs:html` if you have pandoc installed.

### Folder Structure
The repository primarily consists of the folders `qupulse` (source code), `tests` and `doc`.
Expand Down
2 changes: 1 addition & 1 deletion doc/source/concepts/awgs.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.. _hardware:
.. _awgs:

How qupulse models AWGs
-----------------------
Expand Down
34 changes: 19 additions & 15 deletions doc/source/concepts/instantiating.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,19 +7,25 @@ As already briefly mentioned in :ref:`pulsetemplates`, instantiation of pulses i
interpretable representation of a concrete pulse ready for execution from the quite high-level :class:`.PulseTemplate`
object tree structure that defines parameterizable pulses in qupulse.

This is a two-step process that involves
The entry point is the :meth:`.PulseTemplate.create_program` method of the :class:`.PulseTemplate` hierarchy.
It accepts the pulse parameters, and allows to rename and/or omit channels or measurements.
It checks that the provided parameters and mappings are consistent and meet the optionally defined parameter constraints of the pulse template.
The translation target is defined by the :class:`.ProgramBuilder` argument.

#. Inserting concrete parameter values and obtaining a hardware-independent pulse program tree
#. Flattening that tree, sampling and merging of leaf waveforms according to needs of hardware
Each pulse template knows what program builder methods to call to translate itself.
For example, the :class:`.ConstantPulseTemplate` calls :meth:`.ProgramBuilder.hold_voltage` to hold a constant voltage for a defined amount of time while the :class:`.SequncePulseTemplate` forwards the program builder to the sub-templates in order.
The resulting program is completely backend dependent.

This separation allows the first step to be performed in a hardware-agnostic way while the second step does not have
to deal with general functionality and can focus only on hardware-specific tasks. Step 1 is implemented in the
:meth:`.PulseTemplate.create_program` method of the :class:`.PulseTemplate` hierarchy. It checks parameter consistency
with parameter constraints and returns an object of type
:class:`.Loop` which represents a pulse as nested loops of atomic waveforms. This is another object tree structure
but all parameters (including repetition counts) have been substituted by the corresponding numeric values passed into
``create_program``. The :class:`.Loop` object acts as your reference to the instantiated pulse.
See :ref:`/examples/02CreatePrograms.ipynb` for an example on usage of :meth:`.PulseTemplate.create_program`.
**Historically**, there was only a single program type :class:`.Loop` which is still the default output type.
As the time of this writing there is the additional :class:`.LinSpaceProgram` which allows for the efficient representation of linearly spaced voltage changes in arbitrary control structures. There is no established way to handle the latter yet.
The following describes handling of :class:`.Loop` object only via the :class:`qupulse.hardware.HardwareSetup`.

The :class:`.Loop` class was designed as a hardware-independent pulse program tree for waveform table based sequencers.
Therefore, the translation into a hardware specific format is a two-step process which consists of the loop object creation as a first step
and the transformation of that tree according to the needs of the hardware as a second step.
However, the AWGs became more flexibly programmable over the years as discussed in :ref:`awgs`.

The first step of this pulse instantiation is showcased in :ref:`/examples/02CreatePrograms.ipynb` where :meth:`.PulseTemplate.create_program` is used to create a :class:`.Loop` program.

The second step of the instantiation is performed by the hardware backend and transparent to the user. Upon registering
the pulse with the hardware backend via :meth:`qupulse.hardware.HardwareSetup.register_program`, the backend will determine which
Expand All @@ -37,8 +43,6 @@ by the driver with its neighbors in the execution sequence until the minimum wav
optimizations and merges (or splits) of waveforms for performance are also possible.

In contrast, the Zurich Instruments HDAWG allows arbitrary nesting levels and is only limited by the instruction cache.
However, this device supports increment commands which allow the efficient representation of linear voltage sweeps which is **not** possible with the :class:`.Loop` class.

However, as already mentioned, the user does not have to be concerned about this in regular use of qupulse, since this
is dealt with transparently in the hardware backend.

The section :ref:`program` touches the ideas behind the current program implementation i.e. :class:`.Loop`.
The section :ref:`program` touches the ideas behind the current program implementations i.e. :class:`.Loop` and :class:`.LinSpaceProgram`.
19 changes: 17 additions & 2 deletions doc/source/concepts/program.rst
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,26 @@ The dimensions are named by the channel names.

Programs are created by the :meth:`~.PulseTemplate.create_program` method of `PulseTemplate` which returns a hardware independent and un-parameterized representation.
The method takes a ``program_builder`` keyword argument that is propagated through the pulse template tree and thereby implements the visitor pattern.
If the argument is not passed :py:func:`~qupulse.program.default_program_builder()` is used instead which is :class:`.LoopBuilder` by default, i.e. the program created by default is of type :class:`.Loop`. The available program builders, programs and their constituents like :class:`.Waveform` and :class:`.VolatileRepetitionCount` are defined in th :mod:`qupulse.program` subpackage and it's submodules. There is a private ``qupulse._program`` subpackage that was used for more rapid iteration development and is slowly phased out. It still contains the hardware specific program representation for the tabor electronics AWG driver. Zurich instrument specific code has been factored into the separate package ``qupulse-hdawg``. Please refer to the reference and the docstrings for exact interfaces and implementation details.
If the argument is not passed :func:`~qupulse.program.default_program_builder()` is used instead which is :class:`.LoopBuilder` by default, i.e. the program created by default is of type :class:`.Loop`. The available program builders, programs and their constituents like :class:`.Waveform` and :class:`.VolatileRepetitionCount` are defined in th :mod:`qupulse.program` subpackage and it's submodules. There is a private ``qupulse._program`` subpackage that was used for more rapid iteration development and is slowly phased out. It still contains the hardware specific program representation for the tabor electronics AWG driver. Zurich instrument specific code has been factored into the separate package ``qupulse-hdawg``. Please refer to the reference and the docstrings for exact interfaces and implementation details.

The :class:`.Loop` default program is the root node of a tree of loop objects of arbitrary depth.
Each node consists of a repetition count and either a waveform or a sequence of nodes which are repeated that many times.
Iterations like the :class:`.ForLoopPT` cannot be represented natively but are unrolled into a sequence of items.
The repetition count is currently the only property of a program that can be defined as volatile. This means that the AWG driver tries to upload the program in a way, where the repetition count can quickly be changed. This is implemented via the ``VolatileRepetitionCount`` class.

A much more capable program format is :class:`.LinSpaceNode` which efficiently encodes linearly spaced sweeps in voltage space by utilizing increment commands. It is build via :class:`.LinSpaceBuilder`. Increment commands are available in the HDAWG command table.
A much more capable program format is :class:`.LinSpaceNode` which efficiently encodes linearly spaced sweeps in voltage space by utilizing increment commands. It is build via :class:`.LinSpaceBuilder`.
The main complexity of this program class is the efficient handling of interleaved constant points.
The increment and set commands do not only carry a channel and a value but also a dependency key which encodes the dependence of loop indices.
This allows the efficient encoding of

.. code:: python

for idx in range(10):
set_voltage(CONSTANT) # No dependencies
set_voltage(OFFSET + idx * FACTOR) # depends on idx with

for _ in range(10): # loop
set_voltage(CONSTANT, key=None)
increment_by(FACTOR, key=(FACTOR,))

The motivation is that increment commands with this capability are available in the HDAWG command table.
4 changes: 1 addition & 3 deletions doc/source/concepts/pulsetemplates.rst
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ In some cases, it is desired to write a pulse which partly consists of placehold

You can do some simple arithmetic with pulses which is implemented via :class:`.ArithmeticPulseTemplate` and :class:`.ArithmeticAtomicPulseTemplate`. The relevant arithmetic operators are overloaded so you do not need to use these classes directly.

In the future might be pulse templates that allow conditional execution like a `BranchPulseTemplate` or a `WhileLoopPulseTemplate`.

All of these pulse template variants can be similarly accessed through the common interface declared by the :class:`.PulseTemplate` base class. [#pattern]_

As the class names are quite long the recommended way for abbreviation is to use the aliases defined in :py:mod:`~qupulse.pulses`. For example :class:`.FunctionPulseTemplate` is aliased as :class:`.FunctionPT`
Expand Down Expand Up @@ -52,7 +50,7 @@ To obtain a pulse ready for execution on the hardware from a pulse template, the

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, we proceed in several steps.

First, the :meth:`.PulseTemplate.create_program` checks parameter consistency with parameter constraints and translates the pulse template into an instantiated program object, which is then further interpreted and sequenced by the hardware backend code (in :py:mod:`~qupulse.hardware`).
First, the :meth:`.PulseTemplate.create_program` checks parameter consistency with parameter constraints and translates the pulse template into an instantiated program object. The nature of this program depends on the targeted hardware and is determined by the ``program_builder`` keyword argument. This program is further interpreted and sequenced by the hardware backend code (in :py:mod:`~qupulse.hardware`).

See :ref:`instantiating` for a more in-depth explanation of instantiating pulses.

Expand Down
5 changes: 4 additions & 1 deletion qupulse/_program/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@
#
# SPDX-License-Identifier: GPL-3.0-or-later

"""This is a private package meaning there are no stability guarantees."""
"""This is a private package meaning there are no stability guarantees.

Large parts of this package where stabilized and live now in :py:mod:`qupulse.program`.
"""
Loading
Loading