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 aQuantumMachine
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 aQuantumMachine
-
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 thatv_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 (ifFalse
).
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:
playing a pulse to the element (identical to a
play()
statement)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.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 toNone
, raw results will not be saved (note: must be explicitly set toNone
). 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 withqm.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
orFalse
- 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 instream_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")