Skip to content

Commit

Permalink
Fill in a lot of empty doc sections.
Browse files Browse the repository at this point in the history
  • Loading branch information
blakejohnson committed Jun 19, 2017
1 parent 88084ea commit 598af89
Show file tree
Hide file tree
Showing 3 changed files with 183 additions and 5 deletions.
26 changes: 25 additions & 1 deletion doc/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,28 @@ single-channel real output is still a TODO.

## Configuration Options

Lorem ipsum...
QGL depends on a number of global configuration options defined in `config.json`
in the QGL package directory. If this file cannot be found when the package is
loaded, it is created and populated with these default parameters
```json
{
"AWGDir": "/my/path/to/awg/",
"ChannelLibraryFile": "/my/path/to/ChannelParams.json",
"PulsePrimitivesLibrary": "standard",
"cnot_implementation": "CNOT_CR",
"PlotBackground": "#EAEAF2",
"GridColor": "white"
}
```

These parameters control:

* `AWGDir` - the directory where sequence file outputs of the compiler should be
saved.
* `ChannelLibraryFile` - path to the channel parameters JSON file
* `PulsePrimitivesLibrary` - `standard` or `all90`; the latter uses only 90 rotations
to create all operations (e.g. `X = X90 + X90`)
* `cnot_implementation` - names another method to delegate implementation of
`CNOT`; usually `CNOT_simple` or `CNOT_CR`
* `PlotBackground` - hex string controlling background color of plots
* `GridColor` - hex string controlling color of grid lines in plots
23 changes: 23 additions & 0 deletions doc/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,26 @@ different default CNOT implementation by modifying the 'cnot_implementation' key
in QGL's config.json configuration file.

## Built-in Basic Sequences

QGL provides many pre-defined methods for sequences commonly used to
characterize a quantum device. These methods are defined in QGL's
`BasicSequences` package and include:

* `RabiAmp`
* `RabiWidth`
* `PulsedSpec`
* `InversionRecovery`
* `Ramsey`
* `HahnEcho`
* `CPMG`
* `SingleQubitRB`
* `TwoQubitRB`

Usage of each is defined in its respective doc string. For instance, at an
ipython prompt, you may type
```shell
In [1]: ?RabiAmp
```
to learn about the `RabiAmp` function. We encourage users to peruse the methods
defined in `BasicSequences` for templates that may be useful in writing their
own QGL programs.
139 changes: 135 additions & 4 deletions doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ ancillary pulse information for things such as event triggers.

All `LogicalChannels` must be mapped to `PhysicalChannels` in order for the QGL
compiler to produce sequence files for the target hardware. The setup of this
mapping is described later in the section on **Channel Library Setup**.
mapping is [described later](config.md#channel-library-setup).

While setup of these channels is important for final sequence compilation, QGL
programs typically refer only to `Qubit` channels. Actions on other channel
Expand Down Expand Up @@ -106,7 +106,7 @@ definition of `C1` in `Cliffords.py` to find our enumeration of the group.

QGL provides only one high-level two-qubit primitives, `CNOT`. The implementation
of CNOT may be chosen by specifying the `cnot_implementation` key in QGL's
config file.
[config file](config.md#configuration-options).

```python
# high-level primitives
Expand All @@ -122,6 +122,14 @@ ZX90_CR(q1, q2) # a ZX90 on Edge(q1, q2) implemented with "echoed"
echoCR(q1, q2) # A "echoed" cross-resonance pulse
```

### Additional Parameters

All QGL pulse primitives accept an arbitrary number of additional keyword
arguments. In particular, any QGL primitive accepts a `length` keyword to modify
the length of the resulting operation. These additional parameters are passed to
the [shape function](#pulse-shapes-and-waveforms) when the QGL compiler
constructs waveforms from `Pulse` objects.

## Sequences and Simultaneous Operations

Programs in QGL are specified using python lists. For example,
Expand All @@ -131,6 +139,16 @@ seq = [X90(q1), X(q1), Y(q1), X90(q1), MEAS(q1)]
```

The elements of the list provide a time-ordered sequence of pulses to execute.
Using the python list to describe sequences allows for the use of python's
powerful list comprehension syntax to describe sequence variations. For
instance, you can concisely write a scan over a rotation angle or delay in a
list comprehension such as:
```python
seq = [[X90(q1), Id(q1, length=d), X90(q1), MEAS(q1)] for d in np.linspace(0, 10e-6, 11)]
```
QGL's compiler assumes that such lists of lists represent a series of related
experiments and schedules them to occur sequentially in the AWG output.

Users express simultaneity in QGL using the `*` operator. For instance,
```python
q1 = QubitFactory("q1")
Expand All @@ -151,6 +169,119 @@ seq = [align(X90(q1)*X90(q2)), align(MEAS(q1)*MEAS(q2), mode="right")]
`align` takes a `mode` argument ("left", "right", or default "center") to
specify a particular pulse alignment within a `PulseBlock`.

## Pulse Shapes
## Composite Pulses

Occasionally one wants to construct a sequence of pulses and treat them as if
the entire sequence were a single pulse. For this, QGL allows pulses to be
joined with the `+` operator. This allows, for example, us to define
```python
def hadamard(q):
return Y90(q) + X(q)
```
and then use `hadmard(q)` just like any other pulse primitive, even though it is
composed of a sequence of two pulses.

## Pulse Shapes and Waveforms

The QGL compiler constructs waveforms to implement the desired quantum
operations. To do this, each pulse has a `shapeFun` (shape function) that is
called with its `shapeParams`. A number of commonly used shapes are defined in
the `PulseShapes` module including:

* `constant` - i.e. a "square" pulse with constant amplitude
* `tanh` - essentially a square pulse with rounded edges
* `gaussian` - a truncated Gaussian shape
* `drag` - the DRAG pulse gives a Gaussian shape with its derivative on the opposite quadrature.
* `gaussOn` - the first half of a truncated Gaussian shape
* `gaussOff` - the second half of a truncated Gaussian shape

The default pulse shape is determined by properties in the [channel
library](config.md#channel-library-setup). However, the QGL programmer may
override the default shape with a keyword argument. For example, to force the
use of square pulse shape we may write:
```python
seq = [X(q1, shapeFun=PulseShapes.constant), MEAS(q1)]
```

One common use case for specifying a shape function is in the construction of
composite pulses. For instance, you may want a square pulse shape with Gaussian
edges rather than those given by the `tanh` function. To do this you might write:
```python
seq = [X(q1, shapeFun=PulseShapes.gaussOn) +\
X(q1, shapeFun=PulseShapes.constant) +\
X(q1, shapeFun=PulseShapes.gaussOff),
MEAS(q1)]
```

Shape functions can be an arbitrary piece of python code that returns a NumPy
array of complex values. Shape functions must accept **all** of their arguments
as keyword arguments. The only arguments that are guaranteed to exist are
`samplingRate` and `length`. The pulse length is always assumed to be units of
seconds; it is up to the shape function to use the passed sampling rate to
convert from time into number of points/samples. As an example, we could define
a ramp shape with
```python
def ramp(length=0, samplingRate=1e9, **kwargs):
numPts = int(np.round(length * samplingRate))
return np.linspace(0, 1, numPts)
```

Then use it with any pulse primitive, e.g.:
```python
seq = [X(q1, shapeFun=ramp)]
```

If your custom shape function requires additional arguments, you must either
arrange for these parameters to exist in the `LogicalChannel`'s `shapeParams`
dictionary, or pass them at the call site. For instance,
```python
def foo(length=0, samplingRate=1e9, bar=1, **kwargs):
numPts = int(np.round(length * samplingRate))
# something involving bar...

seq = [X(q1, bar=0.5, shapeFun=foo)] # bar is passed as a keyword arg
```

See the `PulseShapes` module for further examples.

## Compiling and Plotting

To reduce a pulse sequence to AWG vendor-specific hardware instructions, use the
`compile_to_hardware()` method, e.g.:
```python
seq = [[X90(q1), Id(q1, length=d), X90(q1), MEAS(q1)] for d in np.linspace(0, 10e-6, 11)]
meta_info = compile_to_hardware(seq, 'test/ramsey')
```

This code snippet will create a folder called `test` inside
[`AWGDir`](config.md#configuration-options) and produce sequence files for each
AWG targeted by the `PhysicalChannels` associated with the QGL program. For
instance, if the `q1` channel targeted an AWG named `APS1` and the `M-q1`
channel targeted `APS2`, then the above call to `compile_to_hardware` would
produce two files: `ramsey-APS1.h5` and `ramsey-APS2.h5` in the `test` folder.
It would also produce a *meta information* file `ramsey-meta.json` which
contains data about the QGL program that may be useful for executing the
program in an instrument control platform such as
[Auspex](https://github.com/BBN-Q/Auspex). `compile_to_hardware` returns the
path to this meta info file.

The `plot_pulse_files()` creates a visual representation of the pulse sequence
created by a QGL program. For example,
```python
plot_pulse_files(meta_info)
```
will create an interactive plot where each line represents a physical output
channel of an AWG referenced by the QGL program.

You may also view a QGL program prior to the logical -> physical mapping with
`show()`. For example,
```python
seq = [X90(q1), Id(q1, length=100e-9), X90(q1), MEAS(q1)]
show(seq)
```
will create a plot grid where each subplot shows the operations on individual
`LogicalChannels`.

## Axis Descriptors

Lorem ipsum...
TODO

0 comments on commit 598af89

Please sign in to comment.