qutech / qupulse Goto Github PK
View Code? Open in Web Editor NEWQuantum Computing Toolkit for Qubit Control
Quantum Computing Toolkit for Qubit Control
Conditional pulses (defined via BranchPulseTemplate and LoopPulseTemplate) may rely on hardware triggers (if supported by the devices) to make branching decisions.
Determine how Condition objects can "encode" the required information so that the PulseHardwareUploadInterface can configure the hardware appropriately prior to pulse playback.
Part of #13.
"QuTiP (Quantum Toolbox in Python) is open-source software for simulating the dynamics of open quantum systems." -- http://qutip.org/
Since QuTiP is already used in a variety of projects, it should also be integrated into the qc-toolkit, providing an existing implementation of quantum circuit simulation.
It might also allow for a direct reuse of its object-oriented representation of quantum circuit components or at least inspire a similar structure in this project.
As a user of the pulse library, I would like to be able to specify that (parts of) a pulse should be repeated a fixed number of times without interrupting execution or depending on hardware triggers.
While the desired behavior could be achieved using LoopPulseTemplate with a specifically tailored Condition subclass, maybe a more direct mechanism to express such fixed amounts of iterations would be beneficial.
Possibilities are:
@qutech/owners @qutech/bluhm-group Do you have preferences?
Implement a test in MATLAB which
The current way of defining parameters in the time domain for TablePulseTemplates is cumbersome at best: First, a TimeParameterDeclaration instance has to be created and then, in a separate call, a table entry which refers to this parameter declaration can be added to the table.
This has the disadvantage that a caller could refer to the same time parameter declaration from several table entries he creates.
Furthermore, there is currently no way for TimeParameterDeclarations to refer to each other as mininmum or maximum values which, in theory, allows for entries to swap positions in an instantiation.
For the table (only time values given) [0, t1, t2, 3] it would be convenient, if t2 could refer to t1 as its minimal value (and for t1 to refer to t2 as its maximum value).
As a user of the TablePulseTemplate, I desire that:
Hardware qubits are controlled using voltage signals and their behavior is measured as such. These signals are generated/measured by dedicated hardware devices, i.e., arbitrary waveform generators (AWGs) and data acquisition devices/cards (DAQs). A variety of such devices from multiple manufacturers exist.
Hardware abstraction should, first, abstract from the specifics of a device and, second, from the hardware setup (which single device is connected to which qubit) and offer only a uniform set of input and output channels to layers above as well as means to configure devices through a common interface.
The concept and class hierarchy for pulses, pulse templates and parameters presented in the 3rd meeting should be included in the wiki for documentation purposes .
Part of #13 .
Implement the Condition class and subclasses as proposed in issue #25.
Implement the SequencePulseTemplate class which will be used to build sequences of PulseTemplate objects and thus introducing nesting and reuse in pulse definitions. Implementation should include all methods required to define a pules using the class but not yet the translation to waveforms (see #20).
Part of #13.
Implement the Pulse class which represents an actual instantiation of a PulseTemplate with a corresponding set of Parameter objects, ready for execution on the hardware (after being translated to waveforms).
Part of #13 .
PulseTemplate exposes methods that might not be able to implement because they require information of a single pulse instance rather than a template. These have to be removed from the template or some meaningful semantic for them has to be formulated.
Candidates are:
Tests for TablePulseTemplate are not yet written.
Task of feature #4
Not very high priority as of March 2015
The idea is to provide a simple way to simulate the expected result of programmed gate sequences.
Several complementary options to describe decoherence that will be relevant in different settings should be available.
Going beyond leading order would require additional features, e.g. a parametrization of the actual gate to be used in Monte Carlo modelling.
Check Qutip (qutip.org) to see if that framework can be built upon before independent implementation.
To extract a documentation of the Toolkit I have experimented with doxygen (link) but it is not really optimized for python. It works, but the results look weird, especially since it does not work well with type hints: Each type hint is intepreted as an additional method parameter.
Looking for a better tool I've read of Sphinx which seems to be made for python and I would test it sometime in the future.
Does anyone have experience with commonly used tools for python and knows recommendations/alternatives?
During the last meeting and today we discussed the migration from Matlab to Python and possible interfaces. One approach that deserves further study is to define a clean interface between data acquisition (similar or identical to current special-measure or qtlab) and the pulse-related control utilities. Allowing a variety of data acquisition and instrument control solutions to be compatible could be attractive. In any case, a well defined interface with as few interconnections as possible seems desirable.
As a start, we concluded that Simon would soon start exploring the used of the Matlab-Python interface to generate scan structs in Matlab from Python. This could provide a simple way to continue using our acquisition software together with the new framework.
The alternative is to migrate to QTlab. Here, first steps could be to implement a driver (e.g. for the averaging DLL) to see how well it suits our concept and perhaps a generic driver wrapper to simplify recycling.
In this context, I would like to bring this package to your attention: labcontrol-software.com. It seems to support similar features as special measure, but is likely better documented, implemented less minimalistically and may be easier to use. A downside is that it seems to be on the way to being commercialized. One may debate whether a GUI is good or bad, but it does support Python scripting.
I played around with TablePulseTemplate a bit, trying to build a square pulse. There were a lot of calls to non-existent list methods, etc. I fixed a few of those and pushed my fixed version to a new branch (issue-47). I have found a lot of ambigous points and would ask either @lumip or @j340m3 to have a look anywhere i have put a TODO comment.
As a user of PulseTemplates, I wish to be able to save and load PulseTemplate to/from a persistent storage to simplify reuse. PulseTemplates should be stored in a readable way to allow modification of stored PulseTemplates without invoking the software. It should be possible to either store an entire PulseTemplate hierarchy in a single file or split the hierarchy, store different subtrees in separate files that reference each other.
During the 3rd meeting it was decided to use JSON-files as the primary format of storing PulseTemplates (see #8 for a discussion on different storage mechanisms).
To allow for flexibilty, PulseTemplates should not know how they are stored. This should be encapsualted in a PulseTemplateSerializer object which provides an interface for PulseTemplates to serialize and deserialize their internal information from an abitrary persistent storage.
PulseTemplates need to be identified by a unique name to derive file names and construct meaningful references. However, it may be possible to embed PulseTemplates only relevant for a single hierarchy into the serialization of their parent PulseTemplate. In this case, no identifier is needed.
Proposed changes to the current design:
Introduce new abstract class PulseTemplateSerializer:
PulseTemplate:
In discussion #7, @hbluhm referenced the documentation of the Raytheon BBN Technologies Arbitrary Pulse Sequencer 2 as a device to be considered as well as the PyQLab project maintained by the manufacturer.
Having taken a look at both, it seems that this should integrate reasonably well with the sequencing scheme proposed in #27. The APS2 relies on an instruction set similar to the one we intended to use with some extended functionality. Expanding our instruction set to cover this should be feasible.
The PyQLab project introduces a Quantum Gate Language (QGL) which essentially is an object representation of pulses somewhat comparable to the approach we choose. We might be able to extract some useful ideas from there.
The main difference in pulse representation is the following:
Our approach currently allows users to define pulse templates with optional parameters. We allow nesting using the Composite pattern to feature reuse of already existing templates. This approach allows to create new templates without creating new classes, i.e., without the need to create source code.
PyQLab's approach is create a class if a new pulse template is required and it already provides a set of common templates. Parameters are not encoded into objects as in our approach but rather passed to the template classes during their instantiation. This is a bit simpler than our approach but requires to create a new class (with all required methods to comply with the pulse interface) for each new template and might make reuse of existing template harder. It may be a bit compacter to use in an experiment though (cf. this demo).
Nevertheless, my judgement is that our approach provides more flexibility, so I would recommend we stick to it. Any thoughts @qutech/bluhm-group @qutech/owners ?
Task of feature #4
Generic Gate Properties
1Because this is matrix multiplication the order in which the children are matters!
The typing module from 3.5 is available as a backport to 3.4 on pypi. Do we rely on any other 3.5 features? Why not just include py3.4 in the travis tests and maybe accidentally support the current stable version (especially since it takes the scientific distributions a while to switch once 3.5 is released)? @ekammerloher?
Issue #17 resulted in the implementation of a typchecking decorator that should be used with every method (to avoid the need for manual checking of argument types). Existing methods have to be adapted accordingly.
I think python 3.4 should be used to profit from an evolving language (things like this). Developing with Python 2.7 is like developing on Windows XP.
package | supports | comment |
---|---|---|
NumPy/SciPy | python 3.2+ | since NumPy 1.5.0 / SciPy 0.9.0 |
matplotlib | python 3.1+ | since matplotlib 1.2 |
chaco | python 2.7 | python 3 branch tests run 100% |
PyVisa | python 3.2+ | |
QuTiP | python 2.7+ | On website: "Version 3.3+ is highly recommended." |
nose | python 3.1+ | |
PyTables | python 3.1+ | |
h5py | python 3.2+ |
AWGs typically support branching based on a multi-bit (e.g. 4) digital input signal that is evaluated at certain points. This should eventually also be supported. One option is to extend BranchPulseTemplate to allow multiple branches similar to elif. However, due to hardware restrictions the usage will often be more similar to a C-style switch statement as only the input value rather than arbitrary conditions can be tested.
This feature is somewhat related to #43 as both controls the autonomous response of hardware to external stimuli.
We decided to follow the Google Python Style for this. Another great example covering an exhaustive range of cases can be found here.
I have already adapted a large part of the comments and the two things that remain to be done are:
This change mostly concerns @lumip and @j340m3, but @qutech/bluhm-group should be aware of this.
The hardware interface to allow sequencing(/waveform generation) of pulses seems proposed in #20 is not powerful enough. A better solution is required.
A current approach, which seems to be working, consists of the following:
API: HardwareSequencingInterface, Sequencer
Internal: Class representations of an abstract hardware instruction set for waveform generation with the instructions
Change in PulseTemplate:
Removed generate_waveform(..).
Add build_sequence(Sequencer, Parameters, TargetInstructionBlock).
HardwareSequencingInterface:
Abstract, will be implemented by hardware specific classes. Methods:
Sequencer:
Used to convert the tree structure of pulse templates to a instruction sequence/block. Holds a HardwareSequencingInterface instance. Maintains a stack of pulse templates which are processed one by one. Subtemplates are pushed to the stack by their parent when it is processed.
The translation process is roughly as follows for the different PulseTemplate subtypes:
Invoking Sequencer.build() "compiles" an instruction sequence covering all templates until either the stack is empty or the top-most stock element requires a stop. This sequence can then be easily interpreted by some interpreter to configure the specific hardware devices.
"QTLab is an IPython-based measurement environment. It contains drivers for many instruments and integrates data plotting using gnuplot. Although it is mainly intended to perform automated measurements by creating Python scripts, an extensive set of GTK+-based GUI components is also included, for example to show the current instrument state and to perform simple tasks and measurements." -- http://qtlab.sourceforge.net/
QTLab might provide an existing implementation for hardware abstraction and basic experiment/measurement execution. It is also already employed by several research groups (according to @hbluhm ). Integrating it as far as possible into the qc-toolkit seems desirable.
To this aim, it must be evaluated, to which extent QTLab can be reused and integrated.
The current source code can be found at: http://www.github.com/heeres/qtlab
As a developer I would like to specify types of method arguments and employ some kind of automated type-checking where appropriate. This removes the need to implement such checks manually every time I want to be sure about the type of the object I receive.
Using function annotations (see also this blog post) and decorators (cf. this) would be a nice way to solve this. This code snippet may serve as an example.
This would require a convention on annotation usage as there is no official one that I am aware of (cf. PEP 0008, last point).
The current implementation of Sequencer works in general but has some issues:
Branch.. and Loop.. create new instruction blocks to which their subtemplates are translated and which are later embedded into the main instruction sequence. It may happen that the translation of subtemplates is not completely possible (because of dependence on measurements, etc.) in which case the Sequencer would currently interrupt the translation. Since the Sequencer currently features only one stack which holds elements to be translated, problems will arise if the if-template of a BranchPulseTemplate results in a translation stop and the else-template is not translated (because it was pushed to the translation stack before the if-template).
Currently, Sequencer ignores the requires_stop() method. requires_stop() is meant to indicate that the corresponding SequencingElement/PulseTemplate cannot be translated yet and should be respected by Sequencer. Note that templates containing subtemplates should not let their answer to require_stop depend on their subtemplates, i.e. a SequencePulseTemplate can always be translated even if some subtemplate requires a stop. Branch- and LoopPulseTemplate should make their requires_stop response dependent on the Condition.
Currently, Sequencer creates an entirely new main instruction block in build(). This is erroneous behavior because it prevents continuing a translation after it was interrupted.
Task of feature #1
Generic properties of a qubit:
Spin-quibt specific (derived class)
Some connection to tuning mechanism and resulting information (tune or successor)
In special-measure, the pulses are all stored in one struct, ordered and accessible by their IDs. There is one global database struct in which the default pulses are stored. For a new experiment, the user has to work with his local copy where he overwrites unneeded IDs. When the experiment has been finished, the user saves the whole database file and its report into a folder.
The main database could be rewritten into a SQL-Database. These databases only store basetypes and references, therefore additional steps are necessary to store arbitrary objects.
The main database can be represented in the XML-Format. This format is the standard for data exchange. For each experiment, we generate a subfolder in which the relevant data (pulse, measurements, documentation) will be stored. The pulse file may reference the main database and stores the composition of subpulses.
Criteria | SQL | XML |
---|---|---|
Space efficiency | stores only basetypes and references | one big string storing variable names, structure and values as string |
Speed efficiency | optimized for big databases with 100.000+ | Needs to be parsed for each operation |
Human readability | not readable as is, but exportable | easy to read and understand |
Package dependency (python) | pickling already included (sqlite), ORM needs additional third party packages: SQLObject (LGPL), SQLAlchemy (MIT) | included |
So, in the end, we have the trade-off between having a performant database and having an easy one.
Which setup do you think will fulfill your needs?
Implement the the TablePulseTemplate class (and maybe find a better name while at it) which is the atomic element of pulse definitions. Implementation should include all methods required to define a pules using the class but not yet the translation to waveforms (see #20).
This also includes the implementation of the abstract base class PulseTemplate as well as ParameterDeclaration and auxialiary classes.
Part of #13 .
Gates are logical operations on a single or multiple qubits. Their associated control signals are called pulses. The two concepts are strongly connected. Gates and pulses have the following properties:
pulse and gate definitions somewhat overlap. We should find one term for it and stick to it. The way I try to separate the two is to always use gate down to the physical qubit level, where pulse becomes appropriate. Gates are then logical operations on qubits and may be static, whereas pulses depend on the qubit it is acting on, calibration, etc.
The top level corresponds to algorithms, the middle one to things like simulated versions of physical qubits or logical qubits and the bottom level is the level of real physical qubits, calibration and pulses.
We need to make sure the imports work. I suggest explicitly setting all explicitly or empty init.py's (both work, I tried). The current construct is unnecessarily complicated and aimed at large projects with independent subpackages (think spirits)
The module file pulses/SequencePulseTemplate defines a Mapping class that is used in the SequencePulseTemplate class to map parameters given to that class to its sub-PulseTemplates. This can mean changing the name and giving a function that mathematically transforms parameter values. This is exactly what we need also for issue #44 . However, the Mapping class represent a mapping from an incoming parameter set to an outgoing parameter set. For issue #44, a mapping from parameter set to a single parameter is needed.
What is to be done?:
Patrick, Simon and I decided to move the generation of voltage values per sample via interpolation from TablePulseTemplates into a get_interpolated_voltage_values method of TablePulseTemplate. Sequencer (and corresponding classes) should make use of this method and hence some interfaces need to be adapted.
Qubit objects(?) should bundle all the information relevant for a physical (or simulated) qubit, e.g. associated hardware, parameters for control pulses, other qubits to which it can couple, a qubit model.
Qubit objects should interface with pulse objects, e.g. to provide parameters for pulses, allow the implementation of algorithms in terms of qubits. Somehow, calibration measurements (that will change a lot over time) must be executable for qubits and groups of qubits.
Note: The legacy code (pulsecontrol) is not qubit-aware at all.
To guarantee easy readability and maintainability of the code, conventions for syntax, documentation and testing must be established and followed by the developers.
Such conventions must first be established and documented in the wiki (https://github.com/qutech/qc-toolkit/wiki/Coding-Conventions).
The pulse class hierarchy intends to let PulseTemplate objects control their translation to waveforms via a hardware-dependent Sequencer object. It is not yet clear, how the interface of Sequencer and the interaction of PulseTemplate and Sequencer must look like. Specifying this is crucial for implementation.
Part of #13 .
Travis CI is a continuous integration tool for github projects, performing tests on each push to ensure that code is working as intended. It should be used by our project and must configured accordingly.
If possible, maybe we should separate tests of the actual code and "meta"-tests for missing documentation.
The purpose of the Pulse class is currently unclear and needs to be refined.
In the current design, it adds no real value but I feel like some representation of pulses as instantiated pulse templates is required.
As a user of the pulse library, I want to be able to express that execution of a pulse should pause and wait for a trigger before continuing (without returning control to the software in the meantime).
As a user of the pulse library, I want to be able to formulate dependencies/constraints between parameters in a pulse template definition.
@qutech/owners @qutech/bluhm-group This was mentioned briefly during the last meeting and I didn't catch it all I think. Can you elaborate what exactly is required and maybe provide an example?
Many pulses will have variable parameters that are not known when the pulse is defined. Examples include:
Type 3 are currently handled through pardefs in pulsegroups, type 1 by modifying dictionaries. There is probably no sharp boundary between 1 and 2.
One very desirable change is to introduce parameter names for easier information.
Furthermore, there should be mechanism to control how parameter values are propagated through a pulse tree. Some will be taken from qubit - specific or global calibrations, some will be set when a specific experiments is conducted. There will probably be occasions when one wants to override default parameters from the calibrations - e.g. to check if a calibration is still good.
Similar to pulses, the parameters need to be documented. The reference and complexity issue is probably less severe here. Saving the values of all relevant pulses with each measurement might be enough.
I would suggest to develop the concept along these lines:
Users of the software need to specify qubit control pulses of arbitrary complexity used to influence the state of qubits in experiments.
Pulses are elementary control signals (voltage over time) for qubit hardware. Basic pulses can be defined via interpolated time-value-tables or directly as waveforms (specifying a value for every tick for a given sample rate). More complex pulses can be constructed by nesting, i.e., combining existing pulses. Also, conditional branching and looping should be supported.
Pulses can be parameterized, meaning that a pulse definition can be used as a template which only defines a general control signal structure but leaves certain concrete values (e.g. height of a peak or duration of a slope) open until given concrete values.
The more abstract representation of pulses (tables, nesting, conditional logic) must be translated to sequences of time-voltage-values that the hardware can interpret to generate a corresponding control signal.
Pulses are elementary control signals (voltage over time) for qubit hardware. Basic pulses can be defined via pulse tables or directly as waveforms. More complex pulses can be constructed by nesting, i.e., combining existing pulses. Pulses can be parameterized, meaning that a pulse definition can be used as a template which only defines a general control signal structure but leaves certain concrete values (e.g. height of a peak or duration of a slope) open until given concrete values.
Pulses are not aware of the context they are used in, thus are unable to respond to measured hardware data. Therefore, control structures (conditional branching, loops) cannot be realized on pulse level.
Timestreams represent a sequence of pulses executed on a single (output) channel and establish a correspondence between output and input channels. This means, they configure the measurement hardware and input processing in accordance to the pulses which are to be executed.
Furthermore, since they receive data obtained from the hardware, they can also implement control structures, changing the pulses to be executed at runtime. Timestream may be nested to encourage reuse of pulse sequences with control structures.
Additionally, timestreams provide functionality to execute a pulse optimization experiment (or calibration run) by enabling feedback loops, i.e., executing the given pulse sequence, analyzing and evaluating the measured data using a solver to optimize the pulse and then repeating the process.
Control structures are moved from the timestream to the pulse level. Nesting for timestreams is discarded. Thus, the ability to define arbitrary complex control signals is moved entirely into the pulse level. This requires pulses to have some knowledge of their environment at runtime, however they should remain decoupled entirely from the data acquisition software.
Timestreams now only function as a representation of a channel, essentially being pulse dispatchers or drivers for channels for a single run. They are still configured with a sequence of pulses to run, which are then executed in order.
The distinction between pulses and timestreams is that pulses are intended to be representations of reusable, control singals that perform a well-defined operation on a single (qubit) channel. Timestreams specify - for an upcoming experiment or other execution - which pulses should be exeucted on a channel in this concrete execution.
Synchronization between channels (timestreams) is achieved in the following way: All timestreams are guaranteed to start and proceed simultaneously (with the same execution "velocity"). Due to this, pulses are synchronized during the entire execution. Thus, to apply an operation on multiple channels, the corresponding pulses have to be attached to the respective timestreams at the same time. (Later on, objects representing gates on multiple qubits can facilitate this).
To address the last point of criticism, a multichannel pulse can establish this correspondence between individual pulses.
Figure: A pulse node representing conditional branching.
Figure: Example of a complex pulse with branching and loops, composed out of simpler subpulses.
Do you think that these changes address the criticism and fulfills your needs?
There is no standard library included in python which allows to plot a vector, but there are several external libraries that cover this. In Issue #16, matplotlib has been mentioned. Is this your requested library for this @qutech/bluhm-group?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.