QUA Statements Reference

program()

Create a QUA program.

Used within a context manager, the program is defined in the code block below with statement.

Statements in the code block below are played as soon as possible, meaning that an instruction will be played immediately unless it is dependent on a previous instruction. Additionally, commands output to the same quantum elements will be played sequentially, and to different quantum elements will be played in parallel. An exception is that pulses will be implicitly aligned at the end of each for_() loop iteration.

The generated program_name object is used as an input to the execute function of a QuantumMachine object.

Example of creating a QUA program:

with program() as program_name:
    play('pulse1', 'element1')
    wait('element1')

Example of executing the program on a quantum machine:

my_qm.execute(program_name)

where my_qm is an instance of a QuantumMachine

play(pulse, element, duration=None, condition=None, chirp=None, **kwargs)

Play a pulse to an element.

The pulse will be modified according to the properties of the element (see detailed explanation about pulse modifications below), and then played to the OPX output(s) defined to be connected to the input(s) of the element in the configuration.

Parameters
  • pulse (str) – name of the pulse, as defined in the quantum machine configuration.

  • element (str) – name of the quantum element, as defined in the quantum machine configuration.

  • duration – the time to play this pulse, compress or expand the pulse. If not provided, the default pulse duration will be used. It is possible to dynamically change the duration of both constant and arbitrary pulses, see Dynamic pulse duration.

  • condition – will play only if the condition’s value is true

Note

It is possible to scale the pulse’s amplitude dynamically by using the following syntax:

play('pulse_name' * amp(v), 'element')

where v is QUA variable of type fixed. Range of v: -2 to 2 - 2-16 in steps of 2-16.

Moreover, if the pulse is intended to a mixedInputs element and thus is defined with two waveforms, the two waveforms, described as a column vector, can be multiplied by a matrix:

play('pulse_name' * amp([v_00, v_01, v_10, v_11]), 'element'),

where v_ij, i,j={0,1}, are QUA variables of type fixed. Note that v_ij should satisfy -2 <= v_ij <= 2 - 2-16.

Example:

>>> with program() as prog:
>>>     v1 = declare(fixed)
>>>     assign(v1, 0.3)
>>>     play('pulse1', 'element1')
>>>     play('pulse1' * amp(0.5), 'element1')
>>>     play('pulse1' * amp(v1), 'element1')
>>>     play('pulse1' * amp([0.9, v1, -v1, 0.9]), 'element_iq_pair')
pause()

Pause the execution of the job until qm.QmJob.QmJob.resume() is called.

The quantum machines freezes on its current output state.

update_frequency(element, new_frequency, units='Hz', keep_phase=False)

Dynamically update the frequency of the oscillator associated with a given element.

This changes the frequency from the value defined in the quantum machine configuration.

The behavior of the phase (continuous vs. change only frequency) is controlled by the keep_phase parameter and is discussed in Frequency and phase transformations.

Note

Starting from version 0.6, this statement occurs in parallel with pulse playing, and the latency associated with update_frequency() depends on the duration of the play/wait statement that is played in parallel to it.

Parameters
  • element (str) – The quantum element associated with the oscillator whose frequency will be changed

  • new_frequency (int) – The new frequency value to set in units set by units parameter. Range: (0 to 5000000) in steps of 1.

  • units (str) – units of new frequency. Useful when sub-Hz precision is required.

  • keep_phase (bool) – Determine whether phase will be continuous through the change (if True) or only frequency will change (if False).

Example:

>>> with program() as prog:
>>>     update_frequency("q1", 4000000)
update_correction(element, c00, c01, c10, c11)

Updates the correction matrix used to overcome IQ imbalances of the IQ mixer for the next pulses played on the element

Note

Make sure to update the correction after you called update_frequency()

Warning

Calling update_correction will also reset the frame of the oscillator associated with the quantum element.

Parameters
  • element (str) – The quantum element associated with the oscillator whose correction matrix will change

  • c00 (float | QUA variable of type real) – This, together with the subsequent elements, determines the elements of the correction matrix.

  • c01 (float | QUA variable of type real) –

  • c10 (float | QUA variable of type real) –

  • c11 (float | QUA variable of type real) –

Example:

>>> with program() as prog:
>>>     update_correction("q1", 1.0, 0.5, 0.5, 1.0)
measure(pulse, element, stream=None, *outputs)

Perform a measurement of element using pulse.

An element for which a measurement is applied must have outputs defined in the configuration.

A measurement consists of:

  1. playing a pulse to the element (identical to a play() statement)

  2. waiting for a duration of time defined as the time_of_flight in the configuration of the element, and then sampling the returning pulse. The OPX input to be sampled is defined in the configuration of the element.

  3. demodulating and the acquired data from the indicated element’s output at the intermediate_frequency defined in the configuration of the element, using integration weights defined in the configuration of the pulse, and storing the result in the provided variables.

For a more detailed description of the measurement operation, see Measure statement features.

Parameters
  • pulse – name of the pulse, as defined in the quantum machine configuration. Pulse must have a measurement operation.

  • element – name of the element, as defined in the quantum machine configuration. The element must have outputs.

  • stream

    the stream variable which the raw ADC data will be saved and will appear in result analysis scope. You can receive the results with QmJob.result_handles.get("name")(). A string name can also be used. In this case, the name of the result handle should be suffixed by _input1 for data from analog input 1 and _input2 for data from analog input 2.

    If stream is set to None, raw results will not be saved (note: must be explicitly set to None). The raw results will be saved as long as the digital pulse that is played with pulse is high.

  • outputs

    A parameter specifying the source of the demodulation data, the target variable and the demodulation method.

    By calling either demod or integration with the member functions full, sliced, accumulated and moving_window. These functions are documented in the API for AccumulationMethod below.

Multiple output tuples may be defined, for determining the demodulation result with multiple integration weights.

Example:

>>> with program() as prog:
>>>     I = declare(fixed)
>>>     Q = declare(fixed)
>>>     I_stream = declare_stream()
>>>
>>>     # measure by playing 'meas_pulse1' to element 'rr1', do not save raw results.
>>>     # demodulate using 'cos_weights' and store result in I, and also
>>>     # demodulate using 'sin_weights' and store result in Q
>>>     measure('meas_pulse1', 'rr1', None, ('cos_weights', I), ('sin_weights', Q))
>>>
>>>     # measure by playing 'meas_pulse2' to element 'rr1', save raw results to tag 'samples'.
>>>     # demodulate data from 'out1' port of 'rr1' using 'optimized_weights' as integration weights
>>>     # store result in I
>>>     measure('meas_pulse2', 'rr1', 'samples', ('optimized_weights', 'out1', I))
>>>
>>>     # measure by playing 'meas_pulse2' to element 'rr1', save raw results to object 'I_Stream'. Get raw data of
>>>     # analog input 1.
>>>     measure('meas_pulse2', 'rr1', I_Stream)
>>>     with stream_processing():
>>>         I_stream.input1().save_all("raw_I_stream")
>>>
>>> from qm.QuantumMachinesManager import QuantumMachinesManager
>>> qm = QuantumMachinesManager().open_qm({}) # note: config missing here
>>> job = qm.execute(prog)
>>> # ... we wait for the results to be ready...
>>> # raw results can be retreived as follows (here job is a QmJob object:
>>> raw_I_handle = job.result_handles.get("raw_I_stream")
>>> # raw results can be retrieved as follows (here job is a QmJob object and qe was defined with analog 1):
>>> samples_result_handle = job.result_handles.get("samples_input1")
align(*elements)

Align several quantum elements together.

All of the quantum elements referenced in *elements will wait for all the others to finish their currently running statement.

Parameters

*elements (str | sequence of str) – a single quantum element, or list of quantum elements

reset_phase(element)

Resets the phase of the oscillator associated with element. This sets the phase of the currently playing intermediate frequnecy to the value it had at the beginning of the program (t=0).

Note

Reset phase will only reset the phase of the intermediate frequency (\(\omega_{IF}\)) currently in use.

Parameters

element – a quantum element

ramp_to_zero(element, duration=None)

Starting from the last DC value, gradually lowers the DC to zero for duration *4nsec

If duration is None, the duration is taken from the element’s config

Warning

This feature does not protect from voltage jumps. Those can still occur, i.e when the data sent to the analog output is outside the range -0.5 to 0.5 - 216 and thus will have an overflow.

Parameters
  • element (str) – element for ramp to zero

  • duration (int | None) – time , in multiples of 4nsec. Range: [4, 224] in steps of 1, or None to take value from config

wait(duration, *elements)

Wait for the given duration on all provided elements.

During the wait command the OPX will output 0.0 to the elements.

Parameters
  • duration (int | QUA variable of type int) – time to wait, in multiples of 4nsec. Range: [4, 224] in steps of 1.

  • *elements (str | sequence of str) – elements to wait on

Warning

In case the value of this is outside the range above, unexpected results may occur.

Note

The purpose of the wait operation is to add latency. In simple cases, the latency added will be exactly the same as that specified by the QUA variable or literal used. However, in other cases an additional computational latency may be added. If the actual wait time has significance, such as in characterization experiments, the actual wait time should always be verified with a simulator.

wait_for_trigger(element, pulse_to_play=None)

Wait for an external trigger on the provided element.

During the command the OPX will play the pulse supplied by the :pulse_to_play parameter

Warning

The maximum allowed voltage value for the digital trigger is 1.8V. A voltage higher than this can damage the controller.

Parameters
  • pulse_to_play (str) – the name of the pulse to play on the element while waiting for the external trigger. Must be a constant pulse. Can be None to play nothing while waiting.

  • element (str) – element to wait on

save(var, stream_or_tag)

Stream a QUA variable, or a QUA array cell. the variable is streamed and not immediately saved (see Stream Processing). In case result_or_tag is a string, the data will be immediately saved to a result handle under the same name.

If result variable is used, it can be used in results analysis scope see stream_processing() if string tag is used, it will let you receive result with qm.QmJob.QmJob.result_handles. The type of the variable determines the stream datatype, according to the following rule:

  • int -> int64

  • fixed -> float64

  • bool -> bool

Note

Saving arrays as arrays is not currently supported. Please use a QUA for loop to save an array.

Warning

A variable updated as a result of a measure statement will return with a signed 16.16 bit format, and must be manually right-shifted by 12 bits when loaded with QmJob.result_handles.get("tag").fetch_all().

Example:

>>>     # basic save
>>>     a = declare(int, value=2)
>>>     save(a, "a")
>>>
>>>     # fetching the results from python (job is a QmJob object):
>>>     a_handle = job.result_handles.get("a")
>>>     a_data = a_handle.fetch_all()
>>>
>>>     # save the third array cell
>>>     vec = declare(fixed, value=[0.2, 0.3, 0.4, 0.5])
>>>     save(vec[2], "ArrayCellSave")
>>>
>>>     # array iteration
>>>     i = declare(int)
>>>     array = declare(fixed, value=[x / 10 for x in range(1, 30)])
>>>     with for_(i, 0, i < array.length(), i + 1):
>>>         save(array[i], "array")
Parameters
  • var (QUA variable or a QUA array cell) – A QUA variable or a QUA array cell to save

  • stream_or_tag (str | stream variable) – A stream variable or string tag name to save the value under

frame_rotation(angle, *elements)

Shift the phase of the oscillator associated with a quantum element by the given angle.

This is typically used for virtual z-rotations.

Note

The fixed point format of QUA variables of type fixed is 4.28, meaning the phase must be between -8 and 8 - 228. Otherwise the phase value will be invalid.

Parameters
  • angle (float | QUA variable of type fixed) – The angle to to add to the current phase (in radians)

  • *elements (str | sequence of str) – A quantum element, or sequence of quantum elements, associated with the oscillator whose phase will be shifted

frame_rotation_2pi(angle, *elements)

Shift the phase of the oscillator associated with a quantum element by the given angle in units of 2pi radians.

This is typically used for virtual z-rotations.

Note

Unlike the case of frame_rotation(), this method performs the 2-pi radian wrap around of the angle automatically.

Parameters
  • angle (float | QUA variable of type fixed) – The angle to to add to the current phase (in 2pi radians)

  • *elements (str | sequence of str) – A quantum element, or sequence of quantum elements, associated with the oscillator whose phase will be shifted

reset_frame(*elements)

Shift the frame of the oscillator associated with a quantum element by the given angle.

Used to reset all of the frame updated made up to this statement.

Parameters

*elements (str | sequence of str) – A quantum element, or sequence of quantum elements, associated with the oscillator whose phase will be shifted

assign(var, _exp)

Set the value of a given QUA variable, or of a QUA array cell

Parameters
  • var (QUA variable) – A QUA variable or a QUA array cell for which to assign

  • _exp (QUA expression) – An expression for which to set the variable

Example:

>>> with program() as prog:
>>>     v1 = declare(fixed)
>>>     assign(v1, 1.3)
>>>     play('pulse1' * amp(v1), 'element1')
if_(expression)

If flow control statement in QUA.

To be used with a context manager.

The QUA code block following the statement will be executed only if expression evaluates to true.

Parameters

expression – A boolean expression to evaluate

Example:

>>> x=declare(int)
>>> with if_(x>0):
>>>     play('pulse', 'element')
else_()

Else flow control statement in QUA.

To be used with a context manager.

Must appear after an if_() statement.

The QUA code block following the statement will be executed only if expression in preceding if_() statement evaluates to false.

Example:

>>> x=declare(int)
>>> with if_(x>0):
>>>     play('pulse', 'element')
>>> with else_():
>>>     play('other_pulse', 'element')
for_each_(var, values)

Flow control: Iterate over array elements in QUA.

It is possible to either loop over one variable, or over a tuple of variables, similar to the zip style iteration in python.

To be used with a context manager.

Parameters
  • var (QUA variable | tuple of QUA variables) – The iteration variable

  • values (list of literals | list of tuples of literals | Qua array | tuple of Qua arrays) – A list of values to iterate over or a QUA array.

Example:

>>> x=declare(fixed)
>>> y=declare(fixed)
>>> with for_each_(x, [0.1, 0.4, 0.6]):
>>>     play('pulse' * amp(x), 'element')
>>> with for_each_((x, y), ([0.1, 0.4, 0.6], [0.3, -0.2, 0.1])):
>>>     play('pulse1' * amp(x), 'element')
>>>     play('pulse2' * amp(y), 'element')

Warning

This behaviour is changed and is no longer consistent with python zip. Instead of sending a list of tuple as values, you now need to send a tuple of lists The first list containning the values for the first variable, and so on. The prvious behavior expected the first value to be a tuple of first values for all variable, the second value is the second value tuple for all variables etc.

while_(cond=None)

While loop flow control statement in QUA.

To be used with a context manager.

Parameters

cond (QUA expression) – an expression which evaluates to a boolean variable, determines if to continue to next loop iteration

Example:

>>> x = declare(fixed)
>>> assign(x, 0)
>>> with while_(x<=30):
>>>     play('pulse', 'element')
>>>     assign(x, x+1)
for_(var=None, init=None, cond=None, update=None)

For loop flow control statement in QUA.

To be used with a context manager.

Parameters
  • var (QUA variable) – QUA variable used as iteration variable

  • init (QUA expression) – an expression which sets the initial value of the iteration variable

  • cond (QUA expression) – an expression which evaluates to a boolean variable, determines if to continue to next loop iteration

  • update (QUA expression) – an expression to add to var with each loop iteration

Example:

>>> x = declare(fixed)
>>> with for_(var=x, init=0, cond=x<=1, update=x+0.1):
>>>     play('pulse', 'element')
infinite_loop_()

Infinite loop flow control statement in QUA.

To be used with a context manager.

Optimized for zero latency between iterations, provided that no more than a single quantum element appears in the loop.

Note

In case multiple quantum elements need to be used in an infinite loop, it is possible to add several loops in parallel (see example).

Example:

>>> with infinite_loop_():
>>>     play('pulse1', 'element1')
>>> with infinite_loop_():
>>>     play('pulse2', 'element2')
L(value)

Creates an expression with a literal value

Parameters

value – int, float or bool to wrap in a literal expression

class DeclarationType

An enumeration.

declare(t, **kwargs)

Declare a single QUA variable or QUA vector to be used in subsequent expressions and assignments.

Declaration is performed by declaring a python variable with the return value of this function.

Parameters

t

The type of QUA variable. Possible values: int, fixed, bool, where:

int

a signed 32-bit number

fixed

a signed 4.28 fixed point number

bool

either True or False

Key value

An initial value for the variable or a list of initial values for a vector

Key size

If declaring a vector without explicitly specifying a value, this parameter is used to specify the length of the array

Returns

The variable or vector

Warning

some QUA statements accept a variable with a valid range smaller than the full size of the generic QUA variable. For example, wait() accepts numbers between 4 and 224. In case the value stored in the variable is larger than the valid input range, unexpected results may occur.

Example:

>>> a = declare(fixed, value=0.3)
>>> play('pulse' * amp(a), 'element')
>>>
>>> array1 = declare(int, value=[1, 2, 3])
>>> array2 = declare(fixed, size=5)
declare_stream(**kwargs)

Declare a QUA output stream to be used in subsequent statements To retrieve the result - it must be saved in the stream processing block.

Declaration is performed by declaring a python variable with the return value of this function.

Note

if the stream is an ADC trace, decalring it with the syntax declare_strean(adc_trace=True) will add a buffer of length corresponding to the pulse length.

Returns

A _ResultSource object to be used in stream_processing()

Example:

>>> a = declare_stream()
>>> measure('pulse', 'element', a)
>>>
>>> with stream_processing():
>>>     a.save("tag")
>>>     a.save_all("another tag")
class AccumulationMethod

A base class for specifying accumulation method in measure statement. Not to be instantiated.

full(iw, target, element_output='')

Perform an ordinary demodulation/integration. See Full demodulation.

Parameters
  • iw (str) – integration weights

  • target (QUA variable) –

  • element_output – (optional) the output of a quantum element from which to get ADC results

sliced(iw, target, samples_per_chunk: int, element_output='')

Perform a demouldation/integration in which the demodulation/integration process is split into chunks and the value of each chunk is saved in an array cell. See Sliced demodulation.

Parameters
  • iw (str) – integration weights

  • target (QUA array) –

  • samples_per_chunk (int) – The number of ADC samples to be used for each chunk is this number times 4. Minimal value: 7

  • element_output – (optional) the output of a quantum element from which to get ADC results

accumulated(iw, target, samples_per_chunk: int, element_output='')

Same as sliced(), however the accumulated result of the demodulation/integration is saved in each array cell. See Accumulated demodulation.

Parameters
  • iw (str) – integration weights

  • target (QUA array) –

  • samples_per_chunk (int) – The number of ADC samples to be used for each chunk is this number times 4. Minimal value: 7

  • element_output – (optional) the output of a quantum element from which to get ADC results

moving_window(iw, target, samples_per_chunk: int, chunks_per_window: int, element_output='')

Same as sliced(), however the several chunks are accumulated and saved to each array cell. See Accumulated demodulation.

Parameters
  • iw (str) – integration weights

  • target (QUA array) –

  • samples_per_chunk (int) – The number of ADC samples to be used for each chunk is this number times 4. Minimal value: 7

  • chunks_per_window (int) – The number of chunks to use in the moving window

  • element_output – (optional) the output of a quantum element from which to get ADC results

stream_processing()

A context manager for the creation of Stream Processing pipelines.

Each pipeline defines an analysis process that is applied to every stream item. A pipeline must be terminated with a save/save_all terminal, and then can be retrieved with QmJob.result_handles.

There are two save options: save_all will save every stream item, save will save only last item.

A pipeline can be assigned to python variable, and then reused on other pipelines. It is ensured that the common part of the pipeline is processed only once.

Example of creating a results analysis:

with stream_processing():
    a.save("tag")
    a.save_all("another tag")

Example of retrieving saved result:

QmJob.result_handles.get("tag")