CHANGELOG
0.33.1
New features since last release
Bug fixes
Fixed
NonLinearFluxVectorhandling of the ForLoop to mach the QbloxCompiler behavior. #1126Fixed a mismatch between
FlatTop’s duration andenvelope, were the waveform’senvelopehad length duration + 1. #1122Fixed a bug in the
Calibrationcrosstalk matrix where theinter_crosstalk’s new_matrix was not correctly calculated. Now it behaves as intended. #1121Fixed a bug where
CrosstalkMatrix.to_array()crashed instead of creating the right array when some field of the matrix dictionary where missing (missing values of the matrix), this should default to the identity (values of 1 in the diagonal and 0 outside the diagonal). Now it creates an array even if there are missing elements of the matrix and defaults them to 0 or 1 if those elements are in the diagonal of the matrix. Also fixed thestrrepresentation of the same crosstalk matrix as the same missing values were represented with ones instead of zeroes. #1125
0.33.0
New features since last release
Added Qblox automatic non-linear crosstalk compensation inside qprogram. This feature requires a
NonLinearCrosstalkMatrixas the input crosstalk matrix and it makes use of the features given byNonLinearFluxVector.
It functions much like the linear crosstalk compensation as it modifies the qprogram to adjust the flux buses into their correct bias, in this case the compensation is non-linear.
As the conversion to the new bias is non-linear, the loops given to the qblox Q1ASM cannot be linear and are therefore unpacked limiting the amount of instructions to be given to the Q1ASM sequencer. As well as the qp.play waveforms given, if those are arbitrary and inside a loop, it can lead to a waveform memory limitation. Square pulses and qp.set_offset does not have this limitation.
Added
NonLinearFluxVectorclass for managing per-bus flux offsets and gain values with crosstalk compensation across multi-loop sweeps.Unlike
FluxVector,NonLinearFluxVectorworks directly withVariableandVariableExpressionobjects so that offsets and gains can sweep over loop dimensions without materialising large arrays up front. It is designed to be driven by a compiler that callsset_loop/exit_loopas it walks aQProgramblock tree.Usage example:
import numpy as np from qililab.core.variables import Domain, Variable from qililab.qprogram.blocks import ForLoop, Parallel from qililab.qprogram.crosstalk_matrix import NonLinearCrosstalkMatrix from qililab.qprogram.flux_vector import NonLinearFluxVector from qililab.qprogram.operations import SetGain, SetOffset from qililab.waveforms import Square nlxtalk = NonLinearCrosstalkMatrix.from_array(...) # (...set up xtalk...) phi = Variable("phi", Domain.Voltage) theta = Variable("theta", Domain.Voltage) nlfv = NonLinearFluxVector() nlfv.set_crosstalk_from_bias(nlxtalk, {"flux_0": 0.1, "flux_1": 0.2, "flux_2": 0.3}) nlfv.set_loop(ForLoop(variable=phi, start=0.0, stop=1.0, step=0.5)) # 3 steps → loop_1 nlfv.set_loop(ForLoop(variable=theta, start=0.0, stop=4.0, step=1.0)) # 5 steps → loop_2 nlfv.set_element(SetOffset(bus="flux_0", offset_path0=phi)) nlfv.set_element(SetGain(bus="flux_1", gain=theta)) offsets = nlfv.get_corrected_offsets() # shape (5, 3) per bus plays = nlfv.get_corrected_play({"flux_0": Square(0.5, 100)}) # shape (5, 3) per busAdded
NonLinearCrosstalkMatrixclass extendingCrosstalkMatrixto support nonlinear flux crosstalk correction between buses. The nonlinear correction models SQUID-mediated coupling using a Bessel-series expansion of the periodic SQUID nonlinearity:$$deltaphi_i = 2 cdot text{amp}*{ij} sum*{k=1}^{K} frac{J_k(kbeta_{ij})}{kbeta_{ij}} sin(2pi k phi_j)$$
where $beta_{ij}$ and $text{amp}_{ij}$ are per-bus-pair parameters stored in
beta_c_matrixandnon_lin_amp_matrixrespectively. Entries set toNoneindicate no nonlinear coupling for that pair.Key additions:
set_non_linear_params(bus_i, bus_j, beta_c, amplitude): sets the Bessel modulation parameter and amplitude for a given bus pair.get_non_linear_flux_terms(flux): computes the nonlinear correction vector for a given flux operating point.flux_to_bias(flux): converts target flux values to hardware bias values including nonlinear corrections, applying the inverse of the linear crosstalk matrix on top.from_linear(linear_crosstalk_matrix): creates aNonLinearCrosstalkMatrixfrom an existingCrosstalkMatrix, copying all linear parameters and initializing nonlinear entries toNone.
Usage example:
xtalk = NonLinearCrosstalkMatrix.from_linear(existing_crosstalk)
xtalk.set_non_linear_params("qubit_flux_0", "coupler_flux_2", beta_c=-0.234, amplitude=-0.021)
xtalk.set_non_linear_params("qubit_flux_3", "coupler_flux_2", beta_c=-0.253, amplitude=-0.021)
bias = xtalk.flux_to_bias({"qubit_flux_0": 0.1, "qubit_flux_3": 0.2, "coupler_flux_2": 0.05})
Added
NonLinearFluxVectorclass for managing per-bus flux offsets and gain values with crosstalk compensation across multi-loop sweeps. This class is in qililab.qprogram.flux_vector. The originalFluxVectorhas been moved to this module.Unlike
FluxVector,NonLinearFluxVectorworks directly withVariableandVariableExpressionobjects so that offsets and gains can sweep over loop dimensions without materialising large arrays up front. It is designed to be driven by a compiler that callsset_loop/exit_loopas it walks aQProgramblock tree.Usage example:
import numpy as np from qililab.core.variables import Domain, Variable from qililab.qprogram.blocks import ForLoop, Parallel from qililab.qprogram.crosstalk_matrix import NonLinearCrosstalkMatrix from qililab.qprogram.flux_vector import NonLinearFluxVector from qililab.qprogram.operations import SetGain, SetOffset from qililab.waveforms import Square nlxtalk = NonLinearCrosstalkMatrix.from_array(...) # (...set up xtalk...) phi = Variable("phi", Domain.Voltage) theta = Variable("theta", Domain.Voltage) nlfv = NonLinearFluxVector() nlfv.set_crosstalk_from_bias(nlxtalk, {"flux_0": 0.1, "flux_1": 0.2, "flux_2": 0.3}) nlfv.set_loop(ForLoop(variable=phi, start=0.0, stop=1.0, step=0.5)) # 3 steps → loop_1 nlfv.set_loop(ForLoop(variable=theta, start=0.0, stop=4.0, step=1.0)) # 5 steps → loop_2 nlfv.set_element(SetOffset(bus="flux_0", offset_path0=phi)) nlfv.set_element(SetGain(bus="flux_1", gain=theta)) offsets = nlfv.get_corrected_offsets() # shape (5, 3) per bus plays = nlfv.get_corrected_play({"flux_0": Square(0.5, 100)}) # shape (5, 3) per busExtended
VariableExpressioncapabilities (Qblox backend only) The capabilities ofVariableExpressionhave been extended, and remain exclusive to the Qblox backend.Previously, this type of expression was only supported in the Time Domain. It is now also available in the Voltage Domain, where it can be used to modify values in
qprogramvia the offset or the gain. The Time Domain behavior is unchanged. The updates described below therefore apply only to Voltage Domain operations.A combination of variables is now possible (Voltage Domain only), as shown below.
qp = ql.Qprogram() gain1 = qp.variable("gain1", ql.Domain.Voltage) gain2 = qp.variable("gain2", ql.Domain.Voltage) qp.set_gain("bus", gain1 + gain2)These expressions are subject to some restrictions:
Expression chaining is not supported: at most two components (a variable and a constant, or two variables) are allowed. For example, the following code will raise a
NotImplementedError:qp = ql.Qprogram( gain1 = qp.variable("gain1", ql.Domain.Voltage) qp.set_gain("bus", 10 + gain1 + 30) )Note: unary negation of a variable (e.g.
- gain) counts as two components (it is rewritten as0 - gain), so combining it with an additional term (e.g.- gain - 10) is also expression chaining and raisesNotImplementedError.Only addition (
+) and subtraction (-) are supported. The following raise aTypeError:*,@,/,//,%,**,&,|,^,<<,>>,>,<,>=,<=,+=,-=,*=,/=. Boolean constants also raise aValueError. Takingabs()of a variable raises aNotImplementedError.Mixing variables of different domains (e.g.
gain + freq) raises aValueError.Using a
VariableExpressioninset_offsetwith independent I and Q paths raises aNotImplementedError.Using a
VariableExpressionwith crosstalk compensation across multiple hardware loops raises aNotImplementedError("Double Hardware loops are not yet implemented with the crosstalk."). This will be supported in a future PR.To facilitate the
Q1ASMimplementation, some expressions are internally reorganized in theVariableclass without changing their semantics:gain + (-10) -> gain - abs(10) - 10 + gain -> gain - abs(10) gain - (-10) -> gain + abs(10) - gain -> 0 - gain
Implemented QBlox and QDAC-II automatic crosstalk compensation for
Qprogram. The compiler automatically detects if there is a crosstalk matrix inside platform and implements the crosstalk for any bus inside theCrosstalkclass. To do so, either useplatform.set_crosstalk(crosstalk)or define a crosstalk insidecalibrationand use it throughexecute_qprogram(..., calibration). Withexecute_qprogram(..., crosstalk= True / False)the parameter introduced is a trigger that activates the crosstalk, the user can deactivate crosstalk compensation by setting this flag as False. The flag is True by default but if no crosstalk has been introduce throughplatform.set_crosstalk(crosstalk)orexecute_qprogram(..., calibration)no crosstalk will be applied as none exists.For QDAC-II: The crosstalk modifies the internal structure of the
QProgram, it changes any play or set offset into a set of plays and offsets of each bus of the crosstalk. It also takes into account different loops. With crosstalk, this example qprogram:r_wf = ql.Square(amplitude=1.0, duration=1000) flux_wf = ql.Arbitrary( samples=np.array([0, 0, 0, 0, 0, 0, 0, 0.1, 0.2, 0.3, 0.4, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.4, 0.3, 0.2, 0.1, 0]) ) qp_qdac = ql.QProgram() freq = qp_qdac.variable(label="frequency", domain=ql.Domain.Frequency) with qp_qdac.average(10): qp_qdac.set_offset(bus="qdac_flux2", offset_path0=0.3) with qp_qdac.for_loop(variable=freq, start=10e6, stop=100e6, step=10e6): # QDAC TRIGGER GENERATION qp_qdac.qdac.play(bus="qdac_flux1", waveform=flux_wf, dwell=2) qp_qdac.set_offset(bus="qdac_flux2", offset_path0=-0.2) qp_qdac.set_trigger(bus="qdac_flux1", duration=10e-6, outputs=1, position="start") # QBLOX WAIT TRIGGER qp_qdac.wait_trigger(bus="readout", duration=4) qp_qdac.set_frequency(bus="readout", frequency=freq) qp_qdac.sync() qp_qdac.measure( bus="readout", waveform=ql.IQPair(I=r_wf, Q=r_wf), weights=ql.IQPair(I=r_wf, Q=r_wf), ) qp_qdac.wait(bus="readout", duration=100)Turns internally into this (for a crosstalk matrix only including
qdac_flux1andqdac_flux2):... with qp_qdac.average(10): qp_qdac.set_offset(bus="qdac_flux2", offset_path0=offset_2_compensated) qp_qdac.set_offset(bus="qdac_flux1", offset_path0=offset_1_compensated) with qp_qdac.for_loop(variable=freq, start=10e6, stop=100e6, step=10e6): # QDAC TRIGGER GENERATION qp_qdac.qdac.play(bus="qdac_flux2", waveform=flux_wf_crosstalk_compensated_2, dwell=2) qp_qdac.qdac.play(bus="qdac_flux1", waveform=flux_wf_crosstalk_compensated_1, dwell=2) qp_qdac.set_trigger(bus="qdac_flux1", duration=10e-6, outputs=1, position="start") # QBLOX WAIT TRIGGER qp_qdac.wait_trigger(bus="readout", duration=4) qp_qdac.set_frequency(bus="readout", frequency=freq) qp_qdac.sync() qp_qdac.measure( bus="readout", waveform=ql.IQPair(I=r_wf, Q=r_wf), weights=ql.IQPair(I=r_wf, Q=r_wf), ) qp_qdac.wait(bus="readout", duration=100)For QBlox: The
QProgramstructures affected by the crosstalk areqp.set_offset(...),qp.set_gain(...)andqp.play(...)for flux buses. The behavior is similar to theQdacCompilerbut accounting for the complexity of Qblox compilation. With crosstalk, the qprogram structure will look the same as usual, but for each bus inside the crosstalk matrix, the machine will send a flux pulse / offset to compensate the crosstalk. Parallel loops are also available .IMPORTANT: there is a limitation when trying to use a combination of play with different amplitudes and different
set_gain. Since the output is a combination of $amplitude*gain$, the crosstalk would be incorrectly applied if we translate directly. Therefore the gain takes priority when applying the crosstalk.
Improvements
Allowing for multiple hardware loops for gain and offset with crosstalk compensation, such as flux vs flux measurements. This is possible due to the
VariableExpressionwith crosstalk compensation. Removed raisedNotImplementedError("Double Hardware loops are not yet implemented with the crosstalk."). Example qprograms:... square_wf = Square(amplitude=0.1, duration=50) qp = QProgram() offset_1 = qp.variable(label="offset_1", domain=Domain.Voltage) offset_2 = qp.variable(label="offset_2", domain=Domain.Voltage) with qp.for_loop(variable=offset_1, start=0, stop=0.1, step=0.01): with qp.for_loop(variable=offset_2, start=0.1, stop=0, step=-0.01): qp.set_offset(bus="flux1", offset_path0=offset_1) qp.set_offset(bus="flux2", offset_path0=offset_2) ...And after the crosstalk compensation has been applied the qprogram will look internally like this:
... square_wf = Square(amplitude=0.1, duration=50) qp = QProgram() flux_offset_1_1 = qp.variable(label="flux_offset_1_1", domain=Domain.Voltage) # Flux 1 to itself flux_offset_1_2 = qp.variable(label="flux_offset_1_2", domain=Domain.Voltage) # Flux 2 to flux 1 flux_offset_2_1 = qp.variable(label="flux_offset_2_1", domain=Domain.Voltage) # Flux 1 to flux 2 flux_offset_2_2 = qp.variable(label="flux_offset_2_2", domain=Domain.Voltage) # Flux 2 to itself with qp.parallel([ForLoop(flux_offset_1_1, 0, 0.1, 0.01), ForLoop(flux_offset_1_2, 0, 0.1, 0.01)]): with qp.parallel([ForLoop(flux_offset_2_1, 0.1, 0, -0.01), ForLoop(flux_offset_2_2, 0.1, 0, -0.01)]): qp.set_offset(bus="flux1", offset_path0=flux_offset_1_1 + flux_offset_1_2) # Here we require variable extension qp.set_offset(bus="flux2", offset_path0=flux_offset_2_1 + flux_offset_2_2) ...Modified database manager’s
load_by_idto allow a list of ids to return a list of the measurements with said ids. Also added functiondb_manager.get_dc_offsets(id), for recent addition to the measurements database,dc_offsets. #1097
Breaking changes
VariableExpression.extract_variables()andVariableExpression.extract_constants()have been removed. They are replaced byVariableExpression.variables(list of allVariableinstances in the expression) andVariableExpression.constant(the constant term, orNone). #1057
Deprecations / Removals
Documentation
Bug fixes
Fixed a bug in
set_offsetwhere using aVariableon one path and a negative static value on the other would generate amoveinstruction with a negative immediate, which is invalid Q1ASM. #1113Fixed a bug where
qp.qblox.playwithwait_time=0was treated as nowait_timeprovided, producing incorrect Q1ASM. The wait time is now correctly clamped to the minimum valid value of 4 ns. #1114The save_platform function was not saving bus distortions because it wasn’t added to the Bus.to_dict after the refactor. The property has been added. #1100
Fixed a bug for function Platform.set_bias_to_zero(bus_list) where the flux vector was not updated correctly from bias. #1030
Fixed a bug for qdac execution order, the positions were inverted causing issues with the triggering. #1030
Fixed a bug at the QdacCompiler where the dwell time was converted to us twice turning any value to the minimum dwell possible. #1030
Fixed a bug in the Qblox compiler where the bin acquisition index was not incrementing correctly when multiple
measurecalls are used sequentially inside anaverageblock with an outer sweep loop. Each sequential acquire now gets its own bin register initialised to its position offset, and the bin register is advanced by the total number of acquires per sweep step (instead of always 1), so that consecutive acquires write to consecutive bins and the full acquisition matrix is filled correctly. #1098Fixed a bug where the qblox instrument controller parameter
ext_triggerand the qdac instrument controller parameterreference_clockwhere not correctly translated to dictionary from the runcard and therefore not saved withql.save_platform(platform). #1104Fixed bug were the RSWU_SP16TR
InstrumentandInstrumentControllerwouldn’t be registred causingbuild_platformto fail. #1120
0.32.0
New features since last release
Fix
qcodesversion to0.54.3to avoid breaking changes introduced in later releases. #1091Previously,
QProgram.set_offsetrequired both I and Q offsets (offset_path0andoffset_path1) to be of the same type (either both constants or both variables). This restriction has been removed: it is now possible to mix constants and variables between I and Q.qp = ql.QProgram() offset = qp.variable(label="offset", domain=ql.Domain.Voltage) with qp.for_loop(variable=offset, start=0, stop=1, step=0.1): qp.set_offset(bus="drive", offset_path0= offset, offset_path1=0.5) qp.set_offset(bus="drive", offset_path0=0.1, offset_path1=offset)This release introduces a significant architectural refactor of the digital and pulse-related layers, removes legacy dependencies, and aligns naming and abstractions with established superconducting-qubit literature.
All references to Qibo have been removed from the codebase, along with the complete removal of the pulse module. The digital module has been fully restructured around a new, self-contained compilation and transpilation pipeline. This includes the introduction of a native CircuitTranspiler and CircuitToQProgramCompiler. The new CircuitTranspiler is responsible for decomposing circuits into the native gate set, managing logical and physical qubit layouts, and applying optimizations. It is implemented as a linear pipeline of
CircuitTranspilerPassobjects, replacing the previous Router, Placer, and Optimizer components that depended on Qibo-based implementations. Each transpiler pass now has a concrete, narrowly defined responsibility.The following transpiler passes are now implemented and available:
CancelIdentityPairsPass,CircuitToCanonicalBasisPass,FuseSingleQubitGatesPass,CustomLayoutPass,SabreLayoutPass,SabreSwapPass,CanonicalBasisToNativeSetPass, andAddPhasesToDragsFromRZAndCZPass.The IQ waveform class hierarchy has been refactored and unified. A new abstract base class, IQWaveform, has been introduced, from which IQPair now inherits. The
DRAGclass method has been removed from IQPair and replaced by a dedicated IQDrag class. This change ensures consistent handling of all IQ waveforms and enables correct and robust serialization.Finally, the
Draggate has been renamed toRmwto better reflect standard terminology in the literature and to avoid confusion with pulse-level DRAG correction schemes, which are now explicitly implemented via IQDrag. #991Added resistances inside
CrosstalkMatrix()they can be set bycrosstalk.set_resistances()in the same way ascrosstalk.set_offset. Also they can be set inside the calibration file as resistances. #1077Added crosstalk history element within Calibration. The crosstalk history describes the state of the crosstalk at each iteration of the crosstalk calibration, each time a crosstalk calibration is done the user can add an element to the list with
add_intra_crosstalk(flux_offsets, block_diag_xt_matrix)andadd_inter_crosstalk(full_crosstalk_matrix)at every step of the calibration to update thecrosstalk_history["history"]. The user can remove any element on the history that was not correctly implemented withremove_history_step.
The crosstalk history contains the index, the previous matrix and offsets, the updated offsets, block diagonal matrix and full matrix, and the results from intra and inter crosstalk calibration.
As an example of the code the user might run:
calibration = Calibration()
calibration.crosstalk_matrix = crosstalk_matrix
# Intra qubit experiments
calibration.add_intra_crosstalk(flux_offsets, block_diag_xt_matrix)
# Inter qubit experiments
calibration.add_inter_crosstalk(full_crosstalk_matrix)
calibration.save_history()
Improvements
For Qblox, the acquisition matrix needs to be reset at each
initial_setupandacquire_qprogram_resultscall for QRM and QRM-RF instruments. The reset is performed by uploading an empty sequence. This ensures that users do not encounter limitations on the number of available bins due to previously run experiments.The empty sequence uploaded is:
empty_sequence = { "waveforms": {}, "weights": {}, "acquisitions": {}, "program": "", }Previously, the upload cache compared sequence hashes and skipped re-uploading if no changes were detected. However, since the acquisition portion of the sequence is now consistently removed the cache has been removed to ensure the sequence is always re-uploaded.
Previously, the software filters in the
PulseDistortionmodule were normalised by default. This PR changes the default value ofauto_normto False, as the previous behaviour was considered counterintuitive. #1075Implemented a new driver for the Becker Nachrichtentechnik RSWU-SP16TR #1020
For Autocalibration database, moved
sample_nameandcooldownfromAutocalMeasurement(independent experiment) toCalibrationRun(full calibration tree). This way the database does not include redundant information, as these variables do not change from one measurement to another, only in different calibration runs. #1053Added sequence run table to measurements database. This table works similar to calibration run and is intended to store a series of experiment runs one after the other. Added
add_sequence_runto database manager to operate it. Also modified the quibit index on the autocalibration database from integer to string to take into account two qubit gate experiments. #1070Changed internal structure of waveform generation on the qblox compiler. Added a check in the platform for QCM and QRM modules with only one channel. Now whenever a single waveform is given instead of giving this waveform to I and creating an empty Q, it checks first how many channels does it have based on platform:
If it has 2 channels the behavior is the same (waveform to I and an empty Q)
If it has 1 channel, I and Q are identical waveforms and register as one single waveform (effectively doubling the Q1ASM waveform compilation available size and setting the correct amplitude). If the user gives an IQPair regardless, the behavior remains unchanged and a Q wave will be saved in memory but never sent through the machine.
This check is automatic and requires no input from the user aside from setting the runcard correctly. #1076
Breaking changes
All references to Qibo have been removed, and any functionality relying on Qibo-based components has been eliminated. #991
The pulse module has been removed entirely. #991
The digital module has been restructured, replacing the previous Router, Placer, and Optimizer with a new CircuitTranspiler pipeline and CircuitToQProgramCompiler, which may require updates to downstream integrations. #991
The IQ waveform hierarchy has changed: IQWaveform is now the abstract base class, the
DRAGmethod has been removed from IQPair, and users must migrate to IQDrag where applicable. #991The
Draggate has been renamed toRmw, requiring updates to any code referencing the old gate name. #991
Deprecations / Removals
Documentation
Bug fixes
[BUG] - VNA E5080B Driver. Enum Parameters were passing the entire Enum to the device causing an error when setting the parameter. Now the value of the Enum is passed to the device. #1072
Calibration file: The
with_calibrationmethod inqprogramwas not storing the needed information to import blocks, this information is now being stored. Theinsert_blockmethod instructured_qprogramhas been modified such that the block is flattened, hence each element is added separately, rather than adding the block. Adding the block directly was causing problems at compilation because adding twice in a singleqprogramthe same block meant they shared the same UUID. #1050QbloxDraw: Fixed two acquisition-related bugs:.
Acquisition-only programs are now displayed correctly.
Acquisition timing issues caused by wait instructions have been fixed. #1051
QbloxDraw: Variable offsets can now be plotted. #1049
Removed threading for
ExperimentExecutor(). This feature caused a deadlock on the execution if any error is raised inside it (mainly involving the ExperimentsResultsWriter). The threading has been removed as it was only necessary for parallel time tracking. #1055
BSC-15
Improvements
For Autocalibration database, moved
sample_nameandcooldownfromAutocalMeasurement(independent experiment) toCalibrationRun(full calibration tree). This way the database does not include redundant information, as these variables do not change from one measurement to another, only in different calibration runs. #1053
Bug fixes
Calibration file: The
with_calibrationmethod inqprogramwas not storing the needed information to import blocks, this information is now being stored. Theinsert_blockmethod instructured_qprogramhas been modified such that the block is flattened, hence each element is added separately, rather than adding the block. Adding the block directly was causing problems at compilation because adding twice in a singleqprogramthe same block meant they shared the same UUID. #1050QbloxDraw: Fixed two acquisition-related bugs:.
Acquisition-only programs are now displayed correctly.
Acquisition timing issues caused by wait instructions have been fixed. #1051
QbloxDraw: Variable offsets can now be plotted. #1049
Removed threading for
ExperimentExecutor(). This feature caused a deadlock on the execution if any error is raised inside it (mainly involving the ExperimentsResultsWriter). The threading has been removed as it was only necessary for parallel time tracking. #1055
BSC-14
New features since last release
Hardware Loop over the time domain has been implemented for Qblox backend in
QProgram. This allows sweeping wait times entirely in hardware, eliminating the need of software loops (which require uploading multiple Q1ASM). The implementation leverages the different Q1ASM jump instructions to ensure correct execution of theQProgramsync operation.Variable expressions for time domain Variable expressions are now supported in
QProgramfor the time domain. The supported formats are given in ns:constant + time variabletime variable + constantconstant - time variabletime variable - constant
Code example:
qp = QProgram()
duration = qp.variable(label="time", domain=Domain.Time)
with qp.for_loop(variable=duration, start=100, stop=200, step=10):
qp.wait(bus="drive", duration)
qp.sync()
qp.wait(bus="drive", duration - 50)
QbloxDraw: Replaced the fixed qualitative palette (10 colors) with the continuous “Turbo” colorscale. Previously, plotting more than 10 buses caused an index error due to the palette’s limited size. The new implementation samples the continuous colorscale at evenly spaced positions based on the number of buses. #1039
Active reset for transmon qubits in QBlox
Implemented a feedback-based reset for QBlox: measure the qubit, and if it is in the
|1⟩state apply a corrective DRAG pulse; if it is already in|0⟩(ground state), do nothing. This replaces the relaxation time at the end of each experiment with a much faster, conditional reset. This has been implemented as: ``qprogram.qblox.measure_reset(bus: str, waveform: IQPair, weights: IQPair, control_bus: str, reset_pulse: IQPair, trigger_address: int = 1, save_adc: bool = False)``It is compiled by the QBlox compiler as:
latch_rst 4on the control_busplay readout pulse
acquire
sync the readout and control buses
wait 400 ns on the control bus (trigger-network propagation)
set_conditional(1, mask, 0, duration of the reset pulse)→ enable the conditionalPlay the reset pulse on the control bus
set_conditional(0, 0, 0, 4)→ disable the conditional
For the control bus,latch_en 4is added to the top of the Q1ASM to enable trigger latching.
MeasureResetCalibratedhas been implemented to enable the use of active reset with a calibration file. After retrieving the waveforms and weights from the calibration file, the measure reset can be called with: ``qprogram.qblox.measure_reset(bus=’readout_bus’, waveform=’Measure’, weights=’Weights’, control_bus=’drive_bus’, reset_pulse=’Drag’)``. Unlike other methods, this one does not allow a mix of calibrated and non-calibrated parameters is not allowed. This method requires the calibration file to be used consistently acrosswaveform,weight, andreset_pulse; either for all three or for none. An error is raised if this condition is not met. NotesThe 400 ns wait inside
measure_resetis the propagation delay of the Qblox trigger network. This figure is conservative as the official guideline is 388ns.Users may supply any IQPair for the reset_pulse, though DRAG pulses are recommended to minimize leakage.
After
measure_reset, users should insert a further wait as needed to allow the readout resonator to ring down before subsequent operations.On compilation,
cluster.reset_trigger_monitor_count(address)is applied to zero the module’s trigger counter. And the qcodes parameters required to set up the trigger network are implemented by the QbloxQRM class.The Qblox Draw class has been modified so that
latch_rstinstructions are interpreted as await, and allset_conditionalcommands are ignored. #955 #1042
Introduced
electrical_delayas a new setting for the E5080b VNA driver. It is a pure software setting to be used in autoplotting and not a physical parameter of the device. #1037Introduced a Pydantic-powered
QililabSettingsthat centralizes runtime configuration, with the singletonget_settings()pulling values from multiple sources so teams can pick what fits their workflow. Settings still default to sensible values, but can be overridden directly in code by editing the fields (handy for tests or ad-hoc scripts), by exporting environment variables (for exampleQILILAB_EXPERIMENT_RESULTS_BASE_PATH=/data/qililab), or by dropping the same keys into a project-level.envfile that is auto-discovered and parsed. #1025
Improvements
Upgraded requirement:
qpysequence>=0.10.8#1044Improved acquisition result handling in the QBlox Compiler.
Previously, each acquisition was assigned a unique acquisition index, which meant that a single qprogram could only contain up to 32 acquisitions per bus (due to QBlox’s limit of 32 indices). Now, acquisitions at the same nested level reuse the same acquisition index while incrementing the bin index. This removes the 32-acquisition limit in most cases. A
ValueErroris raised only if more than 32 acquisitions occur at different nested levels. Since the results retrieved from QBlox are now intertwined, a new function_unintertwined_qblox_resultshas been introduced inplatform. This function called by_execute_qblox_compilation_output methodandexecute_compilation_outputs_parallelseparates each acquisition into its own QbloxMeasurementResult object. #998Added support for real-time predistortion on Qblox hardware.
The outputs of a QCM can now set an FIR filter and up to four exponential filters (provided as a list). These parameters can be configured via the runcard (example below) and via platform.set_parameter/get_parameter.
The runcard has a new section under each QCM module:
filters: [...]configured by output. The section is optional.The states of a QCM filter are “enabled”, “bypassed” and “delay_comp”. Users can provide a boolean where True is mapped to “enabled” and False is mapped to “bypassed”. When enabling a filter that could cause delay with other module outputs Qililab coerces the state to “delay_comp”. This state ensures pulse timing remains consistent with filtered paths, keeping all outputs synchronized.
Parameters:
Exponential Filters (given by exponential index)
EXPONENTIAL_AMPLITUDE_0 … EXPONENTIAL_AMPLITUDE_3
EXPONENTIAL_TIME_CONSTANT_0 … EXPONENTIAL_TIME_CONSTANT_3
EXPONENTIAL_STATE_0 … EXPONENTIAL_STATE_3
FIR Filters:
FIR_COEFF
FIR_STATE
Note: fir_coeff/FIR_COEFF must contain exactly 32 coefficients.
Below is an example of the filter part of the runcard:
filters: - output_id: 0 exponential_amplitude: [0.8, -1] exponential_time_constant: [6, 8] exponential_state: [True, True, False] fir_coeff: [0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8] fir_state: True - output_id: 1 exponential_amplitude: 0.31 exponential_time_constant: 9 exponential_state: False fir_coeff: [0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8, 0.8] fir_state: FalseBelow is an example of set/get_parameter, the output_id must be provided:
platform.set_parameter(alias=bus_alias, parameter=Parameter.EXPONENTIAL_TIME_CONSTANT_0, value=300, output_id=0) platform.get_parameter(alias=bus_alias, parameter=Parameter.FIR_STATE, output_id=2)When setting/getting any parameter from the platform and giving the bus_alias, if an output_id or channel_id not associated with the bus is given, an exception is raised; and if an output_id instead of a channel_id (and vice versa) has been given an Exception is raised. #981
This update introduces a new mechanism that allows the library to optionally import either full concrete implementations or lightweight stubs, depending on the user’s environment and installed dependencies. As part of this improvement, all Quantum Machines–related components have been reorganized under the
extra/quantum-machinesmodule hierarchy for better modularity and maintainability. Additionally, the Quantum Machines integration has been moved to the[project.optional-dependencies]section of the configuration, enabling users to install it only when needed.For example, to install the base library without any optional dependencies, run:
pip install qililabor
uv syncIf you plan to use the Quantum Machines integration, you can include it during installation using the optional dependency group:
pip install qililab[quantum-machines]or
uv sync --extra quantum-machinesUpdate qblox-instruments to 0.16.0 and qblox firmware to 0.11 #1015
This PR is the beginning of a series that will aim to reduce the length of the Q1ASM, which can be limiting for some experiments. This PR has two distinct improvements:
When possible, waits will be combined together. For example, before this PR the following Q1ASM could be generated:
wait 10 wait 40wait 10 wait 40It will now be generated as:
wait 50It will now be generated as:
wait 50When instructing an
acquire_weighedin Q1ASM, the creation of registers has been optimised. New registers for the weights would be created each time, a dictionaryweight_index_to_registerhas been introduced in the QBlox Compiler to track previously used values of weight and reuse the register if possible. For example, twoacquire_weightedwith the same weight would use 4 registers for the weights (R0, R1, R3, R4):setup: wait_sync 4 set_mrk 0 upd_param 4 main: move 0, R0 move 0, R1 move 0, R2 move 0, R3 move 0, R4 move 0, R5 move 101, R6 move 0, R7 loop_0: play 0, 0, 4 acquire_weighed 0, R5, R4, R3, 100 add R5, 1, R5 play 0, 0, 4 acquire_weighed 1, R2, R1, R0, 100 add R2, 1, R2 add R7, 1, R7 loop R6, @loop_0 set_mrk 0 upd_param 4 stopBut they will now only use 1 register (R1):
setup: wait_sync 4 set_mrk 0 upd_param 4 main: move 0, R0 move 0, R1 move 0, R2 move 101, R3 move 0, R4 loop_0: play 0, 0, 4 acquire_weighed 0, R2, R1, R1, 100 add R2, 1, R2 play 0, 0, 4 acquire_weighed 1, R0, R1, R1, 100 add R0, 1, R0 add R4, 1, R4 loop R3, @loop_0 set_mrk 0 upd_param 4 stop
Added
parametersdictionary to theCalibrationclass, and removed legacy code. #1005platform.execute_qprograms_parallel()now takes a list of bus mappings to allow one bus mapping per qprogram. Parameters for the function have now the same syntax and behaviour: bus_mapping (ist[dict[str, str] | None] | dict[str, str], optional). It can be one of the following: A list of dictionaries mapping the buses in theQProgram(keys )to the buses in the platform (values). In this case, each bus mapping gets assigned to theQProgramin the same index of the list of qprograms passed as first parameter. A single dictionary mapping the buses in theQProgram(keys )to the buses in the platform (values). In this case the same bus mapping is used for each one of the qprograms. None, in this case there is not a bus mapping betweenQProgram(keys )to the buses in the platform (values) and the buses are as defined in each qprogram. It is useful for mapping a genericQProgramto a specific experiment. Defaults to None. calibrations (list[Calibration], Calibration, optional). Contains information of previously calibrated values, like waveforms, weights and crosstalk matrix. It can be one of the following: A list ofCalibrationinstances, one perQPrograminstance in the qprograms parameter. A single instance ofCalibration, in this case the same.Calibrationinstance gets associated to all qprograms. None. In this case no.Calibrationinstance is used. Defaults to None. #996%% submit_job: Added support for sbatch –chdir via a new -c/–chdir option that is propagated through slurm_additional_parameters and also enforced inside the job (os.chdir(…)) so it works with -e local. Made –output mandatory and hardened the output‑assignment check to recognize Assign, AugAssign, AnnAssign, walrus (NamedExpr), and tuple targets. Shipment of the notebook namespace is now safer: only picklable values (via
cloudpickle) are sent, with common pitfalls (modules, loggers, private_names, IPython internals) excluded.--low-priorityis a boolean flag mapping to a sane Slurmnice=10000. Paths are handled withpathlibplusexpanduser/expandvars, the logs directory is created if missing, and imports are harvested conservatively from history (one‑lineimport/from, excludingfrom __future__). Parameter assembly only includes Slurm extras when provided, and the submitted function compiles the code string internally while accepting the output name and optional workdir. The job object is written to bothlocal_nsand the globaluser_nsfor IPython robustness. Log cleanup was rewritten to be cross‑platform and resilient: artifacts are grouped by numeric job‑ID prefix, non‑conforming entries are removed, and only the newestnum_files_to_keepjob groups are retained. #994QbloxDraw now supports passing a calibration file as an argument when plotting from both the platform and qprogram. #977
Previously,
platform.draw(qprogram)andqprogram.draw()returned the plotly object and the raw data being plotted. Now they return only the plotly object. This change ensures:When calling
qprogram.draw()orplatform.draw(qprogram)directly, the figure is displayed.When assigning it to a variable (e.g.,
plotly_figure = qprogram.draw()orplotly_figure = platform.draw(qprogram)), the figure is stored but not automatically shown (sincefigure.show()has been removed from QbloxDraw).
If the user needs access to the underlying data, it can be retrieved as follows:
plotly_figure = qprogram.draw() plotly_figure.data
Note: QbloxDraw class continues to return both, the plotly object and the dictionary of raw data. #963
Previously, QbloxDraw returned only the raw data being plotted. Now, the class returns both the Plotly Figure object and the raw data. This has been extended to qprogram and platform:
plotly_figure, data_draw = qprogram.draw()
plotly_figure, data_draw = platform.draw(qprogram)
The R&S SGS100a driver has now the capability to change the operation mode between normal mode and bypass mode. The default mode is the normal mode. The allowed strings for each mode in the settings are
normalandbypass. If the instrument is reset the native instrument configuration defaults to normal. #957Implementation of the Sudden Net Zero (SNZ) waveform to be able to realise better fidelity two qubit gates. #952
The driver of the VNA has been simplified: all files related to Agilent E5071B have been removed, only Keysight E5080B remains. The file structure has been refactored to align with the architecture used by other instruments in Qililab. The file ‘driver_keysight_e5080b’ is meant to be submitted to the public repo QCoDeS contrib drivers, conditional on their approval. The testing file for the driver ‘test_driver_e50808b.py’, alongside the file used to simulate the instrument ‘Keysight_E5080B.yaml’ will also be submitted. The data acquisition process now follows a status-check-based polling loop. The instrument is queried repeatedly using the command “STAT:OPER:COND?”. Before each retrieval, a delay of 0.5 seconds is introduced to prevent overloading the instrument. The command returns an integer representing a bitmask indicating the status of the VNA’s operation. A bitwise operation is performed to determine the readiness for data retrieval, this is done differently depending on whether the number of averages is 1 or greater:
For averages greater than 1: the data can be acquired when bit 8 is set (typically, bit 10 gets enabled after the first average, hence the command usually returns 1280 in decimal or 10100000000 in binary)
For averages equal to 1: the data can be acquired when bit 10 is set (bit 8 does not get set in this case, the expected response is 1024 in decimal or 10000000000 in binary)
For the plots outputted by Qblox Draw, the name legend will now be a concatenation of the bus name and “Flux”, similar to I and Q when hardware modulation is enabled.
An additional argument has been added, to Qblox Draw, time_window. It allows the user to stop the plotting after the specified number of ns have been plotted. The plotting might not be the exact number of ns inputted. For example, if the time_window is 100 ns but there is a play operation of 150 ns, the plots will display the data until 150 ns. #933
Added measurements databases into the results saving structure all the architecture for them is located inside
results/database.py. Added functionality for stream array using databases throughplatform.database_savingand through the classStreamArray, legacystream_array()function still works as usual for retrocompatibility. #928 #1014Added SQLAlchemy and xarray (usefull tool for measurements) to the dependencies as they are required for databases. #928
Relocated save_results and load_results from data_management to result/result_management.py for structure consistency. The load_results functions has been slightly changed to take into account different structures of data. #928
Add base_path as an input for stream_array and an optional parameter for the experiment class, qililab cannot have the data path hardcoded. #936
In the VNA Driver for Keysight E5080B, an update_settings function has been implemented, it allows to efresh all settings inside qililab by querying the VNA.
The sweep time and sweep time auto parameters have been added in the qcodes like driver and also in the wrapper.
The sims file used to test the qcode like driver file has been moved to a similar location as qcodes (qililabsrcqililabinstrumentssims). #943
Modified Streamarray to allow for np.complexfloat values following VNA results. This process has been automatized and requires no input from the user. #941
VNA Driver Keysight E5080B:
Added triggerring related parameters. The parameters included are: sweep_group_count, trigger_source, trigger_type, trigger_slope, accept_before_armed. The first four have been included in the qcode type driver and the qililab wrapper; the last has only been added to the qcodes type driver to avoid cluttering the qililab code with parameters not required.
The expected data type has been added to all set_parameters
In the initial_setup, all parameters are now set, the conditionals have been removed. Now the VNA itself will show an error if two uncompatible parameters are being set. #944
QbloxDraw:
The code is now tracking real time/classical time. The implications are the following:
A play can interrupt a preceeding play - this replicates the hardware behaviour.
Acquisitions are now plotted, when hovering the mouse on the plot, the user can see the index of the acquisition (they are plotted by default but this can be set to False if desired with the argument ‘acquisition_showing’).
Acquire and Play can overlap each other as they are real time commands - this replicates the hardware behaviour. The integration length of the acquire is retrieved from the platform if given. If plotting directly from qprogram, the integration length is set as the duration of the acquire.
The sub and not commands have been implemented.
If QbloxDraw is given a Q1ASM command it is not programmed for, it will raise a NotImplementedError.
The _handle_play() used to loop through all the waveform indices, now it exits in the loop as soon as I and Q have been found, this is more efficient.
When running the code from the platform, the bus_mapping can be provided.
The overall plotting design has been improved. A plotly colour plaette is used. The I and Q are the same color but in a different shade.
Added the database implementation inside
Experiment.load_db_managerfunction added to platform to add the db_manager. ForExperimentclass, added an input variable (platform.save_experiment_results_in_database) to define if working with databases or not (default set as True), if True, the database is automatically generated using theExperimentvariables as information.
Code example:
...
platform.load_db_manager(db_ini_path = "path") # To load the database manager. Optional path.
platform.save_experiment_results_in_database = True # Default is True.
experiment = Experiment(label="Experiment_name", description = "optional description")
platform.execute_experiment(experiment)
...
Minor modification at database
DatabaseManager, as it now requires the config file to contain abase_path_local,base_path_sharedanddata_write_folder. following the structure:
[postgresql]
user =
passwd =
host = haldir.localdomain
port = 9999
database = postgres
base_path_local = "/mnt/home.local/"
base_path_shared = "/home/"
data_write_folder = "shared_measurement_haldir"
The data automatically selects between the local or shared domains depending on availability, always prioritizing local domains but if not available choosing the shared domain.
Modified
StreamArrayto work with live plot. Now the H5 file has theswmr_modeset as true allowing for live reading andStreamArray’s__enter__and__setitem__havefile.flush()to update the H5 live. Movedcreate_datasetto__enter__instead of__setitem__to allow for live plot while acounting for VNA results with different data structure. Modified theexperiment_completedto set asTrueafter the execution, now in case of a crash the experiment will not be set as Completed. #966 #976Implemented a QDACII compiler for triggered voltage lists together with QDACII - QBlox pulse synchronization. Inside the QDACII drivers the functions to create voltage lists, triggered pulses and play those pulse have been created, to simplify the user interaction with the QDACII a
QdacCompilerhas been created usingQprogram.
The structure of a qprogram combining QDACII and Qblox is exemplified as:
qp = Qprogram()
qp.qdac.play(bus="flux_1", waveform=qdac_volt_list, dwell=dwell, repetitions=repetitions)
qp.set_offset(bus="flux_2", offset=value)
qp.set_trigger(bus="flux_1", duration=duration, outputs=out_trigger, position="start")
# QBLOX WAIT TRIGGER
qp.wait_trigger(bus="readout", duration=4)
# QBLOX PULSE
qp.play(bus="drive", waveform=d_wf)
# READOUT PULSE
qp_rabi.measure(bus="readout", waveform=IQPair(I=r_wf_I, Q=r_wf_Q), weights=IQPair(I=weights_shape, Q=weights_shape))
In this example a pulse is played through QDACII flux line 1 and an offset is played through flux line 2. In the meantime Qblox is waiting for each QDACII pulse repetition. #968
Modified smoothed square waveform class
FlatTop(amplitude, duration, smooth_duration, buffer = 0)which works similar to theSquarewaveform with an additional smoothing on the edges. The only additional parameters are the smoothing duration and the buffer time. InQbloxCompilerif the duration exceeds a threshold of 100 ns the pulses are divide into two arbitrary pulses at the beginning and the end for the smooth parts and a loop of square pulses in the middle, with the exact same behavior asSquarepulses. #969Modified the
experiment_completedto set asTrueafter the execution, now in case of a crash the experiment will not be set as Completed. #972Added new functions to DatabaseManager to support more efficient loading of data for live-plotting application. Such as get_platform and get_qprogram. #979
Added
ql.load_by_id(id)in qililab, This function allows to retrieve the data path of a measurement with the given id without creating aDatabaseManagerinstance. This function is intended to be used inside notebooks using slurm asDatabaseManagercannot be submitted. #986Added Database manager for autocalibration and QiliSDK-Speqtrum. Added Database column structure and added new functions on
DatabaseManagersuch asadd_calibration_run,add_autocal_measurement,add_experiment,load_calibration_by_id,load_experiment_by_idto control such databases. Moved all functions related to databases insideresult/database/. ModifiedStreamArrayandExperimentResultsWriterto accomodate for these databases. #1019
Breaking changes
Modified file structure for functions
save_resultsandload_results, previously located insideqililab/src/qililab/data_management.pyand now located atqililab/src/qililab/result/result_management.py. This has been done to improve the logic behind our libraries. The init structure still works in the same way,import qililab.save_resultsandimport qililab.load_resultsstill works the same way. #928Set database saving and live plotting to
Falseby default during experiment execution. #999
Deprecations / Removals
Documentation
Added the return typings and missing docstring elements for the DatabaseManager class. #1036
Bug fixes
Added
py.typedfile in the root dictionary to mark the library as typed and inform type checkers (mypy, pyright, etc.) that this package ships with usable type hints. #1034Qblox Draw read the dac offsets of RF modules (parameters:
OUT0_OFFSET_PATH0,OUT0_OFFSET_PATH1,OUT1_OFFSET_PATH0andOUT1_OFFSET_PATH1) in Volt, although they are specified in millivolts. This has been fixed by converting the value to Volts. #1033Qblox Draw- When dealing with real time and classical time, the real duration was put instead of the wait duration. Note: do not include this comment in the next release changelog as the bug was not in the previous release.
Fixed a bug in the QBlox Compiler handling of the wait, long waits that were a multiple of 65532 (the maximum wait) up to 65535 were giving out an error. This has been solved by checking if the remainder would be below 4. If the remainder is 0 it appends a wait of 65532 and if the remainder is between 1 and 3, the duration of the last wait is computed as :
(INST_MAX_WAIT + remainder) - INST_MIN_WAIT(whereINST_MAX_WAITis 65532 andINST_MIN_WAITis 4) and a wait ofINST_MIN_WAITis added. #1006Exposed
Platformin the global namespace. #1002Fixed a bug in the reshaping of MeasurementResults within the ExperimentResults. #999
Qblox Draw: Previously, when plotting from the platform, the integration length was incorrectly taken from the runcard parameter. However, since Qililab currently only implements acquire_weighted, the integration length should instead be determined by the duration of the weight. This has been corrected and now the behaviour of the acquire is the same when plotting from the platform or the qprogram. The integration length is defined as the duration of the acquire, not the weight, because Qililab ensures they are always equal. As a result, two acquires cannot overlap in Qililab. However, in QbloxDraw’s logic, interruptions remain possible, similar to Play. #982
Removed the unsupported zorder kwarg from QbloxDraw plotting to prevent Plotly errors across environments. #974
A bug on the tests of Qblox Draw has been fixed. Previously, the test compared
figure.datausing the position of items in the list. Since the order of items can change, this caused inconsistent results. The test now compares the data based on the bus name. #965For Qblox Draw, the move commands of the Q1ASM were being read correctly once but were not being updated after - this caused problem with loops.
A 4ns has been added when an acquire_weighed command is added to account for the extra clock cycle #933
Qblox Draw: Corrected bug with time window and nested loops- now after the code exits the recursive loop, the code checks the time window flag status and exits if needed. #937
VNA Driver Keysight E5080B:
The user can now set through the platform the parameters of type Enums, the enums were not being capitalised. - The bounds in the frequency span of the qcodes type driver have been removed as they were wrong.
The bounds of the points in the qcodes type driver have been modified to range from 1 to 100003. #943
QbloxDraw:
The sequencer offsets given from the runcard (offset_i and offset_q in the runcard) were being applied similarly to the DAC offsets, when they should have been treated like the Q1ASM offsets - this has been fixed and those sequencer offsets havee been renamed sequencer_runcard_offset_i and sequencer_runcard_offset_q instead of ac_offsets_i and ac_offsets_q for improved clarity.
get_value() in the QbloxDraw class now checks that the given string is a float, it used to check x.isdigit() which didn’t work for negative values. #945
Fixed a bug for
StreamArraywhile using dictionary structures for the loops. Now the order is correct and the data is saved in the correct h5 file format. #953Quick fix for set_parameter of scope_store_enabled. Now it executes the correct Qblox functions to record the scope. #956 #959
Added an integer transformation for the play pulse duration at the
QbloxCompilercompile. Before this fix, if a user introduced a pulse duration as a float and greater than 100 ns inqp.play, the program would crash with a weir and difficul to trace error report. Now this is fixed. #969Fixed an error inside set_parameter for OUT0_ATT and OUT1_ATT for the QRM-RF and QCM-RF. When the device was disconnected qililab tried to get the non existent device. not it executes as expected. #973
Fixed
FluxVector.set_crosstalk_from_bias(...)andplatform.set_bias_to_zero(...)related to automatic crosstalk compensation. Now the bias is set to 0 correctly and the fluxes are set to the correct value based on the offset. #983Fixed documentation for results
counts, now it warns the user that instead ofnum_avgthey must usenum_bins. #989Fixed an error impeding two instances of QDAC2 to be executed through platform.connect when the runcard included 2 different
qdevil_qdac2controllers insideinstrument_controllers. #990Qblox module
desynch_sequencersnow iterates over instrument_controllers in the Runcard, instead than the plain instruments, solving a bug, where a discrepancy in the runcard between both used to error, trying to desynch an instrument that wasn’t connected (connect loops instrument_controllers, not instruments too). #964Fixed a bug where using stream array with
Calibrationraised an error. This was dues to theStreamArray._get_debug()function, trying to compile a qprogram with calibration waveforms or block without bus mapping. ImprovedStreamArrayerror traceability and added bus_mapping as a variable for proper compilation. #1043
0.29.3 (2025-04-07)
Improvements
The tests for
QbloxDrawhave been modified such that the plots don’t open on the user’s browser when running pytests via VSCode. #924Github Actions now use
pytest-xdistplugin to run tests in parallel. To run tests in parallel locally useuv run pytest -n auto --dist loadfile. The--dist loadfileflag is mandatory to avoid conflicts between tests that edit shared data, and should be planned for removal in the future. #925
Bug fixes
0.29.2 (2025-03-31)
New features since last release
This update marks a significant transition in our workflow by adopting Astral’s uv for dependency management, building, and publishing. With this change, our project now centralizes dependency definitions within a dedicated configuration file
pyproject.toml, ensuring consistent version locking and resolution across all environments. The legacy system for managing dependencies has been replaced with uv’s streamlined approach, which simplifies the maintenance process and reduces potential inconsistencies.
In addition, the build process has been completely overhauled. The old build scripts have been retired in favor of uv’s build command, which compiles the source code, bundles assets, and prepares production-ready artifacts. This change not only standardizes the build process but also introduces enhanced logging and error handling, making it easier to diagnose any issues that arise during the build.
Publishing has also been improved with the integration of uv. The new process automates packaging and deployment, ensuring that artifacts are published in sync with the version specified in the configuration file. This automation minimizes manual intervention and helps maintain consistency in the release process.
Developers should install Astral’s uv globally (for example, running curl -LsSf https://astral.sh/uv/install.sh | sh). After installation, project management is handled through uv CLI. For additional details or troubleshooting, please refer to the official Astral’s uv documentation at https://docs.astral.sh/uv/concepts/projects/.
Implemented automatic mixers calibration for Qblox RF modules. There are to ways to use it. The first one is by setting a parameter in the runcard, which indicates when and which type of calibration is ran.
For the QRM-RF module the parameter is out0_in0_lo_freq_cal_type_default, and the values it can take are off, lo and lo_and_sidebands. The first one is the default value, if set the instrument won’t do any automatic mixers calibration on its own, to avoid unexpected behaviours by default. The second value will suppress the leakage in the LO, and the third one the LO plus the sidebands. The parameter that will trigger this autocalibration everytime is changed in the instrument is out0_in0_lo_freq.
For the QCM-RF module the parameters in the runcard are out0_lo_freq_cal_type_default and out1_lo_freq_cal_type_default, and the values are the same one that for the QRM-RF described above. The parameters that will trigger this autocalibration everytime is changed in the instrument are out0_lo_freq and out1_lo_freq.
The second way to use this autocalibration is to trigger it manually using the Platform instance by calling its method Platform.calibrate_mixers(). As input parameters you will need to specify the alias for the bus where the RF instrument is, the cal_type which allows to specify one of the three values described above, and the channel_id for which mixer you would like to calibrate.
channel_id = 0
cal_type = "lo"
alias_drive_bus = "drive_line_q1_bus"
platform.calibrate_mixers(alias=alias_drive_bus, cal_type=cal_type, channel_id=channel_id)
channel_id = 0
cal_type = "lo_and_sidebands"
alias_readout_bus = "readout_line_q1_bus"
platform.calibrate_mixers(alias=alias_readout_bus, cal_type=cal_type, channel_id=channel_id)
Warnings rise if a value that is not off, lo or lo_and_sidebands are used.
#917
Implemented Crosstalk automatic implementation through the experiment class. The crosstalk can be added through the
Calibrationfile or by creating aCrosstalkMatrix. The crosstalk implementation inside theExperimentclass is:
experiment = ql.Experiment(label="liveplot_test")
flux_x = experiment.variable("flux_x", ql.Domain.Flux)
flux_z = experiment.variable("flux_z", ql.Domain.Flux)
experiment.set_crosstalk(crosstalk=crosstalk_matrix) # to see the values to be applied on the sample
with experiment.for_loop(variable=flux_x, start=0, stop=0.4, step=0.01):
with experiment.for_loop(variable=flux_z, start=0, stop=0.4, step=0.01):
experiment.set_parameter(alias="flux_x1", parameter=ql.Parameter.FLUX, value=flux_x)
experiment.set_parameter(alias="flux_z1", parameter=ql.Parameter.FLUX, value=flux_z)
experiment.execute_qprogram(qp)
Note that not giving a crosstalk matrix implies working with the identity. Warnings rise while creating the experiment to inform the user of this. #899
Implemented crosstalk to the
platform.set_parameterfunction through the parameterParameter.FLUX. This flux parameter automatically applies the crosstalk calibration upon the implied fluxes and executes aset_parameterwithParameter.VOLTAGE,Parameter.CURRENTorParameter.OFFSETdepending on the instrument of the bus. Two new functions have been implemented inside platform:add_crosstalk(), to add either theCrosstalkMatrixor theCalibrationfile andset_flux_to_zero(), to set all fluxes to 0 applying aset_parameter(bus, parameter.FLUX, 0)for all relevant busses An example of this implementation would be:
platform.add_crosstalk(crosstalk_matrix)
platform.set_parameter("flux_ax_ac", ql.Parameter.FLUX, 0.1)
platform.set_flux_to_zero()
Improvements
Modified the
CrosstalkMatrixandFluxVectorclasses to fit for the crosstalk matrix implementation insideExperimentandPlatform. Now both classes update following the specifications and needs of experimentalists. #899
Bug fixes
Correction of bugs following the implementation of the qblox drawing class. The user can now play the same waveform twice in one play, and when gains are set as 0 in the qprogram they are no longer replaced by 1 but remain at 0. Some improvements added, the RF modules are now scaled properly instead of on 1, when plotting through qprogram the y axis now reads Amplitude [a.u.], and the subplots have been removed, all the lines plot in one plot. #918
Fixed an issue involving D5a initial setup where the channel id was not correctly set by id index.
0.29.1 (2025-03-27)
New features since last release
QBlox: An oscilloscope simulator has been implemented. It takes the sequencer as input, plots its waveforms and returns a dictionary (data_draw) containing all data points used for plotting.
The user can access the Qblox drawing feature in two ways:
Via platform (includes runcard knowledge)
with platform.session(): platform.draw(qprogram=qprogram)Note that if it is used with a Quantum Machine runcard, a ValueError will be generated.
Via QProgram (includes runcard knowledge)
qp = QProgram() qprogram.draw()
Both methods compile the qprogram internally to generate the sequencer and call
QbloxDraw.draw(self, sequencer, runcard_data=None, averages_displayed=False) -> dict. #901
Improvements
Now the Rohde & Schwarz will return an error after a limit of frequency or power is reached based on the machine’s version. #897
QBlox: Added support for executing multiple QProgram instances in parallel via the new method
platform.execute_qprograms_parallel(qprograms: list[QProgram]). This method returns a list ofQProgramResultscorresponding to the input order of the provided qprograms. Note that an error will be raised if any submitted qprograms share a common bus.with platform.session(): results = platform.execute_qprograms_parallel([qprogram1, qprogram2, qprogram3])
Deprecations / Removals
Remove the check of forcing GRES in slurm. #907
Bug fixes
D5a instrument now does not raise error when the value of the dac is higher or equal than 4, now it raises an error when is higher or equal than 16 (the number of dacs). #908
0.29.0 (2025-03-17)
New features since last release
We have introduced an optimization in the QbloxCompiler that significantly reduces memory usage when compiling square waveforms. The compiler now uses a heuristic algorithm that segments long waveforms into smaller chunks and loops over them. This optimization follows a two-pass search:
First Pass: The compiler tries to find a chunk duration that divides the total waveform length evenly (i.e., remainder = 0).
Second Pass: If no exact divisor is found, it looks for a chunk duration that leaves a remainder of at least 4 ns. This leftover chunk is large enough to be stored or handled separately.
Each chunk duration is restricted to the range ([100, 500]) ns, ensuring that chunks are neither too small (leading to excessive repetitions) nor too large (risking out-of-memory issues). If no duration within ([100, 500]) ns meets these remainder constraints, the compiler defaults to using the original waveform in its entirety. #861 #895
Raises an error when the inputed value for the QDAC is outside of the bounds provided by QM. Done in 3 ways, runcard, set_parameter RAMPING_ENABLED and set_parameter RAMPING_RATE. #865
Enable square waveforms optimization for Qblox. #874
Implemented ALC, IQ wideband and a function to see the RS models inside the drivers for SGS100a. #894
Improvements
Updated qm-qua to stable version 1.2.1. And close other machines has been set to True as now it closes only stated ports. #854
Improvements to Digital Transpilation:
Move
optimizeflag, for actual optional optimizations (& Improveoptimizeword use in methods names)Make
Transpilation/execute/compileonly for single circuits (unify code standard acrossqililab)Make
Transpilationefficient, by not constructing theCircuitclass so many times, between methodsPass a transpilation
kwargsas a TypedDict instead of so many args inplatform/qililab’sexecute(...)Improve documentation on transpilation, simplifying it in
execute()’s, and creating Transpilation new section.
Added optimizations for Digital Transpilation for Native gates:
Make bunching of consecutive Drag Gates, with same phi’s
Make the deletion of gates with no amplitude
Improved the layout information display and Updated qibo version to the last version (0.2.15), which improves layout handling #869
Now the QM qprogram compiler is able to generate the correct stream_processing while the average loop is inside any other kind of loop, before it was only able to be located on the outermost loop due to the way qprogram generated the stream_processing. #880
The user is now able to only put one value when setting the offset of the bus when using Qblox in the qprogram. Qblox requires two values hence if only 1 value is given, the second will be set to 0, a warning will be given to the user. #896
For Qblox compiler, all latched parameters are updated before a wait is applied. The update parameter has a minimum wait of 4 ns, which is removed from the wait. If the wait is below 8ns it is entirely replaced with the update parameter. #898
Breaking changes
Deprecations / Removals
Documentation
Bug fixes
Addressed a known bug in the qblox where the first frequency and gain settings in a hardware loop are incorrect. The code now includes a workaround to set these parameters a second time to ensure proper functionality. This is a temporary fix awaiting for QBlox to resolve it. #903
Fixed an issue where having nested loops would output wrong shape in QbloxMeasurementResult. #853
Restore the vna driver as it was deleted. #857
Fixed an issue where appending a configuration to an open QM instance left it hanging. The QM now properly closes before reopening with the updated configuration. #851
Fixed an issue where turning off voltage/current source instruments would set to zero all dacs instead of only the ones specified in the runcard. #819
Fixed the shareable trigger in the runcard to make every controller shareable while close other machines is set to false (current default) for QM. Improved shareable for OPX1000 as now it only requires to specify the flag on the fem. Now Octave name inside runcard requires to be the same as the one inside the configuration (now it has the same behavior as the cluster and opx controller). #854
Ensured that turning on the instruments does not override the RF setting of the Rohde, which can be set to ‘False’ in the runcard. #888
0.28.0 (2024-12-09)
New features since last release
Incorporated new check for maximum allowed attenuation in RF modules.
Updated to latest qblox-instruments version. Changed some deprecated code from the new version and the QcmQrm into the more generic Module class.
Added empty handlers for Blocks in QProgram compilers
Support GRES in %%submit_job magic method
Added intermediate frequency to single input lines on qm. The default is 0 (this prevents some bugs from qua-qm). Now it is possible to use the set_parameter IF and qm.set_frequency for buses with single_input.
A new
GetParameteroperation has been added to the Experiment class, accessible via the.get_parameter()method. This allows users to dynamically retrieve parameters during experiment execution, which is particularly useful when some variables do not have a value at the time of experiment definition but are provided later through external operations. The operation returns aVariablethat can be used seamlessly withinSetParameterandExecuteQProgram.Example:
experiment = Experiment() # Get a parameter's value amplitude = experiment.get_parameter(bus="drive_q0", parameter=Parameter.AMPLITUDE) # The returned value is of type `Variable`. It's value will be resolved during execution. # It can be used as usual in operations. # Use the variable in a SetOperation. experiment.set_parameter(bus="drive_q1", parameter=Parameter.AMPLITUDE, value=amplitude) # Use the variable in an ExecuteQProgram with the lambda syntax. def get_qprogram(amplitude: float, duration: int): square_wf = Square(amplitude=amplitude, duration=duration) qp = QProgram() qp.play(bus="readout", waveform=square_wf) return qp experiment.execute_qprogram(lambda: amplitude=amplitude: get_qprogram(amplitude, 2000))Added offset set and get for quantum machines (both OPX+ and OPX1000). For hardware loops there is
qp.set_offset(bus: str, offset_path0: float, offset_path1: float | None)whereoffset_path0is a mandatory field (for flux, drive and readout lines) andoffset_path1is only used when changing the offset of buses that have to IQ lines (drive and readout). For software loops there isplatform.set_parameter(alias=bus_name, parameter=ql.Parameter.OFFSET_PARAMETER, value=offset_value). The possible arguments forql.Parameterare:DC_OFFSET(flux lines),OFFSET_I(I lines for IQ buses),OFFSET_Q(Q lines for IQ buses),OFFSET_OUT1(output 1 lines for readout lines),OFFSET_OUT2(output 2 lines for readout lines). #791Added the
Rampclass, which represents a waveform that linearly ramps between two amplitudes over a specified duration.from qililab import Ramp # Create a ramp waveform from amplitude 0.0 to 1.0 over a duration of 100 units ramp_wf = Ramp(from_amplitude=0.0, to_amplitude=1.0, duration=100)Added the
Chainedclass, which represents a waveform composed of multiple waveforms chained together in time.from qililab import Ramp, Square, Chained # Create a chained waveform consisting of a ramp up, a square wave, and a ramp down chained_wf = Chained( waveforms=[ Ramp(from_amplitude=0.0, to_amplitude=1.0, duration=100), Square(amplitude=1.0, duration=200), Ramp(from_amplitude=1.0, to_amplitude=0.0, duration=100), ] )Added
add_block()andget_block()methods to theCalibrationclass. These methods allow users to store a block of operations in a calibration file and later retrieve it. The block can be inserted into aQProgramorExperimentby callinginsert_block().from qililab import QProgram, Calibration # Create a QProgram and add operations qp = QProgram() # Add operations to qp... # Store the QProgram's body as a block in the calibration file calibration = Calibration() calibration.add_block(name="qp_as_block", block=qp.body) # Retrieve the block by its name calibrated_block = calibration.get_block(name="qp_as_block") # Insert the retrieved block into another QProgram another_qp = QProgram() another_qp.insert_block(block=calibrated_block)Added routing algorithms to
qililabin function of the platform connectivity. This is done passingQiboownRoutersandPlacersclasses, and can be called from different points of the stack.The most common way to route, will be automatically through
qililab.execute_circuit.execute(), or also fromqililab.platform.execute/compile(). Another way, would be doing the transpilation/routing directly from an instance of the Transpiler, with:qililab.digital.CircuitTranspiler.transpile/route_circuit()(with this last one, you can route with a different topology from the platform one, if desired, defaults to platform)Example
from qibo import gates from qibo.models import Circuit from qibo.transpiler.placer import ReverseTraversal, Random from qibo.transpiler.router import Sabre from qililab import build_platform from qililab.digital import CircuitTranspiler # Create circuit: c = Circuit(5) c.add(gates.CNOT(1, 0)) ### From execute_circuit: # With defaults (ReverseTraversal placer and Sabre routing): probabilities = ql.execute(c, runcard="./runcards/galadriel.yml", placer= Random, router = Sabre, routing_iterations: int = 10,) # Changing the placer to Random, and changing the number of iterations: probabilities = ql.execute(c, runcard="./runcards/galadriel.yml", ### From the platform: # Create platform: platform = build_platform(runcard="<path_to_runcard>") # With defaults (ReverseTraversal placer, Sabre routing) probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000) # With non-defaults, and specifying the router with kwargs: probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer= Random, router = (Sabre, {"lookahead": 2}), routing_iterations: int = 20)) # With a router instance: router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the platform's one probabilities = platform.execute(c, num_avg: 1000, repetition_duration: 1000, placer=Random, router=router) ### Using the transpiler directly: ### (If using the routing from this points of the stack, you can route with a different topology from the platform one) # Create transpiler: transpiler = CircuitTranspiler(platform.digital_compilation_settings) # Default Transpilation (ReverseTraversal, Sabre and Platform connectivity): routed_circ, qubits, final_layouts = transpiler.route_circuit(c) # With Non-Default Random placer, specifying the kwargs, for the router, and different coupling_map: routed_circ, qubits, final_layouts = transpiler.route_circuit(c, placer=Random, router=(Sabre, {"lookahead": 2}, coupling_map=<some_different_topology>)) # Or finally, Routing with a concrete Routing instance: router = Sabre(connectivity=None, lookahead=1) # No connectivity needed, since it will be overwritten by the specified in the Transpiler: routed_circ, qubits, final_layouts = transpiler.route_circuit(c, placer=Random, router=router, coupling_map=<connectivity_to_use>)
Added a timeout inside quantum machines to control the
wait_for_all_valuesfunction. The timeout is controlled through the runcard as shown in the example:instruments: - name: quantum_machines_cluster alias: QMM ... timeout: 10000 # optional timeout in seconds octaves: ...Added
shareabletrigger inside runcard for quantum machines controller. The controller is defined in the runcard following this example:instruments: - name: con1 analog_outputs: - port: 1 offset: 0.0 shareable: True
Improvements
Legacy linting and formatting tools such as pylint, flake8, isort, bandit, and black have been removed. These have been replaced with Ruff, a more efficient tool that handles both linting and formatting. All configuration settings have been consolidated into the
pyproject.tomlfile, simplifying the project’s configuration and maintenance. Integration config files likepre-commit-config.yamland.github/workflows/code_quality.ymlhave been updated accordingly. Several rules from Ruff have also been implemented to improve code consistency and quality across the codebase. Additionally, the development dependencies indev-requirements.txthave been updated to their latest versions, ensuring better compatibility and performance. #813platform.execute_experiment()and the underlyingExperimentExecutorcan now handle experiments with multiple qprograms and multiple measurements. Parallel loops are also supported in both experiment and qprogram. The structure of the HDF5 results file as well as the functionality ofExperimentResultsclass have been changed accordingly. #796Added pulse distorsions in
execute_qprogramfor QBlox in a similar methodology to the distorsions implemented in pulse circuits. The runcard needs to contain the same structure for distorsions as the runcards for circuits and the code will modify the waveforms after compilation (insideplatform.execute_qprogram).Example (for Qblox)
buses: - alias: readout ... distortions: - name: exponential tau_exponential: 1. amp: 1. sampling_rate: 1. # Optional. Defaults to 1 norm_factor: 1. # Optional. Defaults to 1 auto_norm: True # Optional. Defaults to True - name: bias_tee tau_bias_tee: 11000 sampling_rate: 1. # Optional. Defaults to 1 norm_factor: 1. # Optional. Defaults to 1 auto_norm: True # Optional. Defaults to True - name: lfilter a: [] b: [] norm_factor: 1. # Optional. Defaults to 1 auto_norm: True # Optional. Defaults to TrueThe execution of
QProgramhas been split into two distinct steps: compilation and execution.Compilation: Users can now compile a
QProgramby calling:
platform.compile_qprogram( qprogram: QProgram, bus_mapping: dict[str, str] | None = None, calibration: Calibration | None = None )This method can be executed without being connected to any instruments. It returns either a
QbloxCompilationOutputor aQuantumMachinesCompilationOutput, depending on the platform setup.Execution: Once the compilation is complete, users can execute the resulting output by calling:
platform.execute_compilation_output( output: QbloxCompilationOutput | QuantumMachinesCompilationOutput, debug: bool = False )If desired, both steps can still be combined into a single call using the existing method:
platform.execute_qprogram( qprogram: QProgram, bus_mapping: dict[str, str] | None = None, calibration: Calibration | None = None, debug: bool = False )Introduced settable attributes
experiment_results_base_pathandexperiment_results_path_formatin thePlatformclass. These attributes determine the directory and file structure for saving experiment results during execution. By default, results are stored withinexperiment_results_base_pathfollowing the format{date}/{time}/{label}.h5. #819Added a
save_plot=Trueparameter to theplotS21()method ofExperimentResults. When enabled (default: True), the plot is automatically saved in the same directory as the experiment results. #819Improved the transpiler, by making it more modular, and adding a
gate_cancellation()stage before the transpilation to natives, this stage can be skipped, together with the oldoptimize_transpilation(), if the flagoptimize=Falseis passed. #823Split execution of annealing programs into two steps: compilation and execution. #825
Added a try and except similar to the dataloss error to restart the measurement in case of random timeout issue for quantum machines. This is a temporary fix and will be deleted once the Quantum Machines team fix their issue.
Breaking changes
Renamed the platform’s
execute_anneal_program()method toexecute_annealing_program()and updated its parameters. The method now expectspreparation_blockandmeasurement_block, which are strings used to retrieve blocks from theCalibration. These blocks are inserted before and after the annealing schedule, respectively.
Major reorganization of the library structure and runcard functionality. Key updates include:
Removed obsolete instruments, such as VNAs.
Removed the
driversmodule.Simplified the
Qbloxsequencer class hierarchy into two main classes:QbloxSequencerandQbloxADCSequencer.Removed
SystemControllerandReadoutSystemController; buses now interface directly with instruments.Introduced a new
channelsattribute to theBusclass, allowing specification of channels for each associated instrument.Removed the
Chipclass and its related runcard settings.Eliminated outdated settings, such as instrument firmware.
Refactored runcard settings into a modular structure with four distinct groups:
instrumentsandinstrument_controllersfor lab instrument setup.busesfor grouping instrument channels.digitalfor digital compilation settings (e.g., Qibo circuits).analogfor analog compilation settings (e.g., annealing programs).
Bug fixes
Fixed minor type bug in
Platform. #846Fixed minor type bug in
CrosstalkMatrix. #825Fixed typo in ExceptionGroup import statement for python 3.11+ #808
Fixed serialization/deserialization of lambda functions, mainly used in
experiment.execute_qprogram()method. The fix depends on thedilllibrary which is added as requirement. #815Fixed calculation of Arbitrary waveform’s envelope when resolution is greater than 1ns. #837
0.27.1 (2024-09-16)
New features since last release
Introduced the possibility to run multiple shots and averages at the same time for
execute_anneal_programmethod. #797Introduced the
Experimentclass, which inherits fromStructuredProgram. This new class enables the ability to set parameters and execute quantum programs within a structured experiment. Added theset_parametermethod to allow setting platfform parameters andexecute_qprogrammethod to facilitate the execution of quantum programs within the experiment. #782Introduced the
ExperimentExecutorclass to manage and execute quantum experiments within the Qililab framework. This class provides a streamlined way to handle the setup, execution, and results retrieval of experiments.Temporary Constraints:
The experiment must contain only one
QProgram.The
QProgrammust contain a single measure operation.Parallel loops are not supported. #790
Introduced the
platform.execute_experiment()method for executing experiments. This method simplifies the interaction with the ExperimentExecutor by allowing users to run experiments with a single call.Example:
# Define the QProgram qp = QProgram() gain = qp.variable(label='resonator gain', domain=Domain.Voltage) with qp.for_loop(gain, 0, 10, 1): qp.set_gain(bus="readout_bus", gain=gain) qp.measure(bus="readout_bus", waveform=IQPair(I=Square(1.0, 1000), Q=Square(1.0, 1000)), weights=IQPair(I=Square(1.0, 2000), Q=Square(1.0, 2000))) # Define the Experiment experiment = Experiment() bias_z = experiment.variable(label='bias_z voltage', domain=Domain.Voltage) frequency = experiment.variable(label='LO Frequency', domain=Domain.Frequency) experiment.set_parameter(alias="drive_q0", parameter=Parameter.VOLTAGE, value=0.5) experiment.set_parameter(alias="drive_q1", parameter=Parameter.VOLTAGE, value=0.5) experiment.set_parameter(alias="drive_q2", parameter=Parameter.VOLTAGE, value=0.5) with experiment.for_loop(bias_z, 0.0, 1.0, 0.1): experiment.set_parameter(alias="readout_bus", parameter=Parameter.VOLTAGE, value=bias_z) with experiment.for_loop(frequency, 2e9, 8e9, 1e9): experiment.set_parameter(alias="readout_bus", parameter=Parameter.LO_FREQUENCY, value=frequency) experiment.execute_qprogram(qp) # Execute the Experiment and display the progress bar. # Results will be streamed to an h5 file. The path of this file is returned from the method. path = platform.execute_experiment(experiment=experiment, results_path="/tmp/results/") # Load results results, loops = load_results(path)Introduced a robust context manager
platform.session()for managing platform lifecycle operations. The manager automatically callsplatform.connect(),platform.initial_setup(), andplatform.turn_on_instruments()to set up the platform environment before experiment execution. It then ensures proper resource cleanup by invokingplatform.turn_off_instruments()andplatform.disconnect()after the experiment, even in the event of an error or exception during execution. If multiple exceptions occur during cleanup (e.g., failures in bothturn_off_instruments()anddisconnect()), they are aggregated into a singleExceptionGroup(Python 3.11+) or a custom exception for earlier Python versions.Example:
with platform.session(): # do stuff...Add crosstalk compensation to
AnnealingProgramworkflow. Add methods toCrosstalkMatrixto ease crosstalk compensation in the annealing workflow #775Add default measurement to
execute_anneal_program()method. This method takes now a calibration file and parameters to add the dispersive measurement at the end of the annealing schedule. #778Added a try/except clause when executing a QProgram on Quantum Machines cluster that controls the execution failing to perform a turning off of the instrument so the _qm object gets removed. This, plus setting the close_other_machines=True by default allows to open more than one QuantumMachines VM at the same time to allow more than one experimentalist to work at the same time in the cluster. #760
Added
__str__method to qprogram. The string is a readable qprogram. #767Added workflow for the execution of annealing programs.
Example:
import qililab as ql platform = ql.build_platform("examples/runcards/galadriel.yml") anneal_program_dict = [ {qubit_0": {"sigma_x" : 0, "sigma_y": 0, "sigma_z": 1, "phix":1, "phiz":1}, "qubit_1": {"sigma_x" : 0.1, "sigma_y": 0.1, "sigma_z": 0.1}, "coupler_0_1": {"sigma_x" : 1, "sigma_y": 0.2, "sigma_z": 0.2} }, {"qubit_0": {"sigma_x" : 0.1, "sigma_y": 0.1, "sigma_z": 1.1}, "qubit_1": {"sigma_x" : 0.2, "sigma_y": 0.2, "sigma_z": 0.2}, "coupler_0_1": {"sigma_x" : 0.9, "sigma_y": 0.1, "sigma_z": 0.1} }, {"qubit_0": {"sigma_x" : 0.3, "sigma_y": 0.3, "sigma_z": 0.7}, "qubit_1": {"sigma_x" : 0.5, "sigma_y": 0.2, "sigma_z": 0.01}, "coupler_0_1": {"sigma_x" : 0.5, "sigma_y": 0, "sigma_z": -1} } ] results = platform.execute_anneal_program(anneal_program_dict=anneal_program_dict, transpiler=lambda delta, epsilon: (delta, epsilon), averages=100_000)Alternatively, each step of the workflow can be executed separately i.e. the following is equivalent to the above:
import qililab as ql platform = ql.build_platform("examples/runcards/galadriel.yml") anneal_program_dict = [...] # same as in the above example # intialize annealing program class anneal_program = ql.AnnealingProgram(platform=platform, anneal_program=anneal_program_dict) # transpile ising to flux, now flux values can be accessed same as ising coeff values # eg. for phix qubit 0 at t=1ns anneal_program.anneal_program[1]["qubit_0"]["phix"] anneal_program.transpile(lambda delta, epsilon: (delta, epsilon)) # get a dictionary {control_flux: (bus, waveform) from the transpiled fluxes anneal_waveforms = anneal_program.get_waveforms() # from here on we can create a qprogram to execute the annealing scheduleAdded
CrosstalkMatrixclass to represent and manipulate a crosstalk matrix, where each index corresponds to a bus. The class includes methods for initializing the matrix, getting and setting crosstalk values, and generating string representations of the matrix.Example:
# Create an empty crosstalk matrix crosstalk_matrix = CrosstalkMatrix() # Add crosstalk values, where the keys are in matrix shape [row][column] crosstalk_matrix["bus1"]["bus2"] = 0.9 crosstalk_matrix["bus2"]["bus1"] = 0.1 # Alternatively, create a matrix from a collection of buses. # All crosstalk values are initialized to 1.0 crosstalk_matrix = CrosstalkMatrix.from_buses({"bus1", "bus2", "bus3"}) # Get a formatted string representation of the matrix # bus1 bus2 bus3 # bus1 \ 1.0 1.0 # bus2 1.0 \ 1.0 # bus3 1.0 1.0 \ print(crosstalk_matrix)Added the Qblox-specific
set_markers()method inQProgram. This method takes a 4-bit binary mask as input, where0means that the associated marker will be open (no signal) and1means that the associated marker will be closed (signal). The mapping between bit indexes and markers depends on the Qblox module that the compiledQProgramwill run on.Example:
qp = QProgram() qp.qblox.set_markers(bus='drive_q0', mask='0111')Added
set_markers_override_enabled_by_portandset_markers_override_value_by_portmethods inQbloxModuleto set markers through QCoDeS, overriding Q1ASM values. #747Added
from_qprogrammethod to theCountsclass to compute the counts of quantum states obtained from aQProgram. TheCountsobject is designed to work for circuits that have only one measurement per bus at the end of the circuit execution. It is the user’s responsibility to ensure that this method is used appropriately when it makes sense to compute the state counts for aQProgram. Note that probabilities can easily be obtained by calling theprobabilities()method. See an example below.Example:
from qililab.result.counts import Counts qp = QProgram() # Define instructions for QProgram # ... qp_results = platform.execute_qprogram(qp) # Platform previously defined counts_object = Counts.from_qprogram(qp_results) probs = counts_object.probabilities()Added
threshold_rotationsargument tocompile()method inQProgram. This argument allows to use rotation angles on measurement instructions if not specified. Currently used to use the angle rotations specified on the runcard (if any) so the user does not have to explicitly pass it as argument to the measure instruction. Used for classification of results in Quantum Machines’s modules. The following example shows how to specify this value on the runcard.Example:
buses: - alias: readout_q0_bus system_control: name: readout_system_control instruments: [QMM] port: readout_line_q0 distortions: [] instruments: - name: quantum_machines_cluster alias: QMM firmware: ... elements: - bus: readout_q0_bus rf_inputs: octave: octave1 port: 1 rf_outputs: octave: octave1 port: 1 time_of_flight: 160 smearing: 0 intermediate_frequency: 10.0e+6 threshold_rotation: 0.5 threshold: 0.03 ...Added
thresholdsargument to_execute_qprogram_with_quantum_machinesmethod inPlatform. This argument allows to threshold results after the execution of theQProgram. It is also a new parameter that can be specified on the runcard for each readout bus. An example of the configuration of this parameter on the runcard can be found above.Added
filterargument inside the qua config file compilation from runcards with qm clusters. This is an optional element for distorsion filters that includes feedforward and feedback, two distorion lists for distorsion compensation and fields in qua config filter. These filters are calibrated and then introduced as compensation for the distorsions of the pulses from external sources such as Bias T. The runcard now might include the new filters (optional):Example:
instruments: - name: quantum_machines_cluster alias: QMM firmware: 0.7.0 ... controllers: - name: con1 analog_outputs: - port: 1 offset: 0.0 filter: feedforward: [0.1,0.1,0.1] feedback: [0.1,0.1,0.1] ...Added loopbacks in the octave config file for qua following the documentation at https://docs.quantum-machines.co/1.2.0/qm-qua-sdk/docs/Guides/octave/?h=octaves#setting-the-octaves-clock. By default only port 1 of the octave is linked with a local demodulator, to work with the rest of the ports at the back ports must be connected based on the Octave Block Diagram [https://docs.quantum-machines.co/1.2.0/qm-qua-sdk/docs/Hardware/octave/#octave-block-diagram%5C]. Where
Synthis one of the possible 3 synths andDmdis one of the 2 demodulators.Example:
- name: quantum_machines_cluster alias: QMM ... octaves: - name: octave1 port: 11252 ... loopbacks: Synth: Synth2 # Synth1, Synth2, Synth3 Dmd: Dmd2LO # Dmd1LO, Dmd2LOAdded delay variables to Qblox qprogram implementation. The delays are added in the runcard in nanoseconds and they can be positive or negative scalars (negative delays will make the rest of buses wait). The delay is a wait applied to each iteration of a loop where the bus is present.
Example:
buses: - alias: readout ... delay: 100
Improvements
Improve Crosstalk matrix
from_busesmethod so it can be a dictionary of buses and crosstalks coefficients. [#784]`https://github.com/qilimanjaro-tech/qililab/pull/784 <https://github.com/qilimanjaro-tech/qililab/pull/784>`_Now platform.get_parameter works for QM without the need of connecting to the machine.
Added the option to get the time of flight and smearing information from the QM cluster #751
Improved the algorithm determining which markers should be ON during execution of circuits and qprograms. Now, all markers are OFF by default, and only the markers associated with the
outputssetting of QCM-RF and QRM-RF sequencers are turned on. #747Automatic method to implement the correct
upsampling_modewhen the output mode is selected asamplified(fluxes), theupsampling_modeis automatically defined aspulse. In this mode, the upsampling is optimized to produce cleaner step responses. #783Automatic method for
execute_qprogramin quantum machines to restart the measurement in case theStreamProcessingDataLossErroris risen byqua-qm, the new feature allows to try again the measurement a number of times equal to the value ofdataloss_tries(default of three). We can define this value atexecute_qprogram(..., dataloss_tries = N)and will only do its intended job in case of working with QM. #788
Breaking changes
Big code refactor for the
calibrationmodule/directory, where allcomparisons,check_parameters,check_data(),check_state(),maintain(),diagnose()and other complex unused methods have been deleted, leaving only linear calibration.Also some other minor improvements like:
drift_timeoutis now a single one for the full controller, instead of a different one for each node.Notebooks without an export are also accepted now (we will only raise error for multiple exports in a NB).
Extended/Improved the accepted type for parameters to input/output in notebooks, thorught json serialization. #746
Variables in
QProgramandExperimentnow require a label.qp = QProgram() gain = qp.variable(label="gain", domain=Domain.Voltage)
Deprecations / Removals
Deleted all the files in
executionandexperimentdirectories (Already obsolete). #749
Documentation
Bug fixes
Hotfix to allow to serialise zeros in yaml. #799
get_parameter for QM did not work due to the lack of the variable
bus_alias in self.system_control.get_parameter. The variable has been added to the function and now get parameter does not return a crash. #751set_parameter for intermediate frequency in quantum machines has been adapted for both OPX+ and OPX1000 following the new requirements for OPX1000 with qm-qua job.set_intermediate_frequency. #764
0.27.0 (2024-06-28)
New features since last release
Added
Calibrationclass to manage calibrated waveforms and weights for QProgram. Included methods to add (add_waveform/add_weights), check (has_waveform/has_weights), retrieve (get_waveform/get_weights), save (save_to), and load (load_from) calibration data.Example:
# Create a Calibration instance calibration = Calibration() # Define waveforms and weights drag_wf = IQPair.DRAG(amplitude=1.0, duration=40, num_sigmas=4.5, drag_coefficient=-2.5) readout_wf = ql.IQPair(I=ql.Square(amplitude=1.0, duration=200), Q=ql.Square(amplitude=0.0, duration=200)) weights = ql.IQPair(I=ql.Square(amplitude=1.0, duration=200), Q=ql.Square(amplitude=1.0, duration=200)) # Add waveforms to the calibration calibration.add_waveform(bus='drive_q0_bus', name='Xpi', waveform=drag_wf) calibration.add_waveform(bus='readout_q0_bus', name='Measure', waveform=readout_wf) # Add weights to the calibration calibration.add_weights(bus='readout_q0_bus', name='optimal_weights', weights=weights) # Save the calibration data to a file calibration.save_to('calibration_data.yml') # Load the calibration data from a file loaded_calibration = Calibration.load_from('calibration_data.yml')The contents of
calibration_data.ymlwill be:!Calibration waveforms: drive_q0_bus: Xpi: !IQPair I: &id001 !Gaussian {amplitude: 1.0, duration: 40, num_sigmas: 4.5} Q: !DragCorrection drag_coefficient: -2.5 waveform: *id001 readout_q0_bus: Measure: !IQPair I: !Square {amplitude: 1.0, duration: 200} Q: !Square {amplitude: 0.0, duration: 200} weights: readout_q0_bus: optimal_weights: !IQPair I: !Square {amplitude: 1.0, duration: 200} Q: !Square {amplitude: 1.0, duration: 200}Calibrated waveforms and weights can be used in QProgram by providing their name.
qp = QProgram() qp.play(bus='drive_q0_bus', waveform='Xpi') qp.measure(bus='readout_q0_bus', waveform='Measure', weights='optimal_weights')In that case, a
Calibrationinstance must be provided when executing the QProgram. (see following changelog entries)Introduced
qililab.yamlnamespace that exports a singleYAMLinstance for common use throughout qililab. Classes should be registered to this instance with the@yaml.register_classdecorator.from qililab.yaml import yaml @yaml.register_class class MyClass: ...MyClasscan now be saved to and loaded from a yaml file.from qililab.yaml import yaml my_instance = MyClass() # Save to file with open(file="my_file.yml", mode="w", encoding="utf-8") as stream: yaml.dump(data=my_instance, stream=stream) # Load from file with open(file="my_file.yml", mode="r", encoding="utf8") as stream: loaded_instance = yaml.load(stream)Added
serialize(),serialize_to(),deserialize(),deserialize_from()functions to enable a unified method for serializing and deserializing Qililab classes to and from YAML memory strings and files.import qililab as ql qp = QProgram() # Serialize QProgram to a memory string and deserialize from it. yaml_string = ql.serialize(qp) deserialized_qprogram = ql.deserialize(yaml_string) # Specify the class for deserialization using the `cls` parameter. deserialized_qprogram = ql.deserialize(yaml_string, cls=ql.QProgram) # Serialize to and deserialize from a file. ql.serialize_to(qp, 'qprogram.yml') deserialized_qprogram = ql.deserialize_from('qprogram.yml', cls=ql.QProgram)Added Qblox support for QProgram’s
measureoperation. The method can now be used for both Qblox and Quantum Machines, and the expected behaviour is the same.readout_pair = IQPair(I=Square(amplitude=1.0, duration=1000), Q=Square(amplitude=0.0, duration=1000)) weights_pair = IQPair(I=Square(amplitude=1.0, duration=2000), Q=Square(amplitude=0.0, duration=2000)) qp = QProgram() # The measure operation has the same behaviour in both vendors. # Time of flight between readout pulse and beginning of acquisition is retrieved from the instrument's settings. qp.measure(bus="readout_bus", waveform=readout_pair, weights=weights_pair, save_adc=True)Update Qibo version to
v.0.2.8. #732
Improvements
Introduced
QProgram.with_bus_mappingmethod to remap buses within the QProgram.Example:
# Define the bus mapping bus_mapping = {"drive": "drive_q0"} # Apply the bus mapping to a QProgram instance mapped_qprogram = qprogram.with_bus_mapping(bus_mapping=bus_mapping)Introduced
QProgram.with_calibrationmethod to apply calibrated waveforms and weights to the QProgram.Example:
# Load the calibration data from a file calibration = Calibration.load_from('calibration_data.yml') # Apply the calibration to a QProgram instance calibrated_qprogram = qprogram.with_calibration(calibration=calibration)Extended
Platform.execute_qprogrammethod to accept a calibration instance.# Load the calibration data from a file calibration = Calibration.load_from('calibration_data.yml') platform.execute_qprogram(qprogram=qprogram, calibration=calibration)Added interfaces for Qblox and Quantum Machines to QProgram. The interfaces contain vendor-specific methods and parameters. They can be accessed by
qprogram.qbloxandqprogram.quantum_machinesproperties.Added
time_of_flightsetting to Qblox QRM and QRM-RF sequencers.
Breaking changes
QProgram interface now contains methods and parameters that have common functionality for all hardware vendors. Vendor-specific methods and parameters have been move to their respective interface.
Examples:
# Acquire method has been moved to Qblox interface. Instead of running # qp.acquire(bus="readout_q0_bus", weights=weights) # you should run qp.qblox.acquire(bus="readout_q0_bus", weights=weights) # Play method with `wait_time` parameter has been moved to Qblox interface. Instead of running # qp.play(bus="readout_q0_bus", waveform=waveform, wait_time=40) # you should run qp.qblox.play(bus="readout_q0_bus", waveform=waveform, wait_time=40) # `disable_autosync` parameter has been moved to Qblox interface. Instead of running # qp = QProgram(disable_autosync=True) # you should run qp = QProgram() qp.qblox.disable_autosync = True # Measure method with parameters `rotation` and `demodulation` has been moved to Quantum Machines interface. Instead of running # qp.measure(bus="readout_q0_bus", waveform=waveform, weights=weights, save_adc=True, rotation=np.pi, demodulation=True) # you should run qp.quantum_machines.measure(bus="readout_q0_bus", waveform=waveform, weights=weights, save_adc=True, rotation=np.pi, demodulation=True)time_of_flightparameter must be added to Qblox QRM and QRM-RF sequencers’s runcard settings.
Deprecations / Removals
0.26.2 (2024-05-28)
New features since last release
Introduce the Two-Step pulse shape to improve readout #730
Deprecations / Removals
Remove qiboconnection_api.block_device() and release_device() #728
0.26.1 (2024-04-26)
Bug fixes
Hotfix for the 2readout problem #720
0.25.1 (2024-03-26)
Bug fixes
Appended hardcoded Time of Flight #711
0.25.0 (2024-03-25)
New features since last release
Improvements
The method
CalibrationNode._execute_notebook()now changes the working directory to the notebook directory before the execution and restores the previous one after the papermill execution. It allows the notebooks now to use relative paths. Also, the initialization ofCalibrationNodewill now contain absolute paths for the attributesnb_folderandnb_path#693
Breaking changes
Added support for Qblox cluster firmware v0.6.1 and qblox-instruments v0.11.2. This changes some of the i/o mappings in the runcard for qblox sequencers so with older versions is broken. #680
Documentation
Added documentation for QProgram.
Bug fixes
Resolved an issue where attempting to execute a previously compiled QUA program on a newly instantiated Quantum Machine resulted in errors due to cache invalidation. #706
0.24.0 (2024-03-05)
New features since last release
Introduced a new parameter,
disable_autosync, to theQProgramconstructor. This parameter allows users to control the automatic synchronization behavior of loops within their quantum programs. By default, the parameter is set toFalse, enabling the compiler to automatically insert synchronization operations at the conclusion of each loop. Users have the option to setdisable_autosynctoTrueto indicate that they prefer to manage loop timing manually. This feature is particularly useful for operations on Qblox hardware, due to its constraints on dynamic synchronization. It’s important to note that Quantum Machines will disregard this setting and adhere to the default synchronization behavior. #694
Breaking changes
The unit of measurement for phases within QProgram has been updated from degrees to radians. #695
Bug fixes
Resolved an issue encountered during the retrieval of results from QProgram executions on Qblox hardware, where acquisition data from other sequencers would unintentionally be deleted. #691
0.23.3 (2024-02-19)
Bug fixes
Fixed an issue when serializing / deserializing a QProgram so results are returned in a standard results class. #688
0.23.2 (2024-02-13)
Bug fixes
Fixed an issue when serializing / deserializing a QProgram that contained an Arbitrary waveform or a DRAG pulse. #686
0.23.1 (2024-02-09)
Bug fixes
Fixes an equality issue of QProgram’s variables that resulted in a slightly different QProgram when serializing and then deserializing. #684
0.23.0 (2024-02-09)
New features since last release
Allow execution of
QProgramthroughplatform.execute_qprogrammethod for Quantum Machines hardware. #648Allow multiple measurements of the same qubit in a single circuit. Also allow measurements in the middle of a circuit. #674
Wait times longer than 2**16-4 (QBLOX maximum wait time in a Q1ASM wait instruction) are now allowed in the middle of a circuit. #674
Add method to get sequencer channel id from qubit index and bus alias #678
Improvements
Added
bus_mappingparameter inQbloxCompiler.compilemethod to allow changing the bus names of the compiled output. #648Improved
QuantumMachinesClusterinstrument functionality. #648Improved execution times of
QProgramwhen used inside a software loop by using caching mechanism. #648Added
DictSerializableprotocol andfrom_dictutility function to enable (de)serialization (from)to dictionary for any class. #659Added method to get the QRM
channel_idfor a given qubit. #664Added Domain restrictions to
Dragpulse,DragCorrectionwaveform andGaussianwaveform. #679Compilation for pulses is now done at platform instead of being delegated to each bus pointing to an awg instrument. This allows easier communication between
pulse_bus_schedulesso that they can be handled at the same time in order to tackle more complex tasks which were not possible otherwise. It also decouples, to a great extent, the instruments and instrument controllers (hardware) from higher level processes more typical of quantum control, which are involved in the pulse compilation to assembly program steps. #651Changed save and load methods using
PyYAMLtoruamel.YAML. #661Qprogram’s qblox compiler now allows iterations over variables even if these variables do nothing. (eg. iterate over nshots) #666
Bug fixes
Added the temporary parameter
wait_timeto QProgram’splaymethod. This allows the user to emulate atime_of_flightduration for measurement until this is added as a setting in runcard. #648Fixed issue with Yokogawa GS200 instrument, that raised an error during initial_setup when the instrument’s output was on. #648
0.22.2 (2024-01-04)
New features since last release
Improvements
QuantumMachinesClustercan be created by translating the runcard into the equivelant QUA config dictionary.initial_setup,turn_onandturn_offmethods have been edited to properly instatiate and calibrate the instrument. #620
Breaking changes
QuantumMachinesManagerhas been renamed toQuantumMachinesClusterandQMMControllertoQuantumMachinesClusterController. #620
Bug fixes
0.22.1 (2023-12-05)
Bug fixes
0.22.0 (2023-11-27)
New features since last release
Added real time results saving capability. #598
Raise an error if a user requests to run a circuit that is longer than
repetition_duration#621Add parameter to the SLURM magic method to configure the time limit of a job. #608
Add magic method to run python code as slurm jobs from Jupyter Notebooks. #600
Implemented
QuantumMachinesCompilerclass to compile QPrograms to QUA programs. #563Implemented
platform.execute_qprogram()method to execute a qprogram on Qblox hardware. #563Added the two main classes need for automatic-calibration,
CalibrationControllerandCalibrationNode#554Added the driver for Quantum Machines Manager and a new QuantumMachinesResult class to handle Quantum Machines instruments. #568
Implemented the
QuantumMachinesMeasurementResultclass to store data acquired from a single instrument. #596
Improvements
Improved the UX for circuit transpilation by unifying the native gate and pulse transpiler under one
CircuitTranspilerclass, which has 3 methods:circuit_to_native: transpiles a qibo circuit to native gates (Drag, CZ, Wait, M) and optionally RZ if optimize=False (optimize=True by default)circuit_to_pulses: transpiles a native gate circuit to aPulseScheduletranspile_circuit: runs both of the methods above sequentiallyWaitgate moved from theutilsmodule tocircuit_transpilation_native_gates#575
Added
infinite_loop()method to QProgram. #563Added
measure()method to QProgram. #563Various improvements in the compilation flow of
QbloxCompiler. #563Updated
qm-qualibrary to latest1.1.5.1. #596
Breaking changes
Deprecations / Removals
Removed the park gate since it is no longer needed #575
Bug fixes
Fixed bug #626, where a regression bug was introduced by adding empty schedules to all flux buses, not only the ones with an AWG registered instrument, as it was intended originally. #628
Fixed bug #579, were now all
yaml.dumpsare done with ruamel, for not losing decimals precisons, and also following the previous bug due to the elimination ofruamel.yaml.round_trip_dump, the version of ruamel in qililab got fixed, and imports where rewritten for more clarity #578
0.21.1 (2023-10-31)
New features since last release
Bug fixes
Fixed bug where executing multiple circuits with each measuring different qubits would launch measurements for previously measured qubits even if those did not have measurements on the circuit currently being executed. #576
ruamel 0.18.0 eliminated
ruamel.yaml.round_trip_dump, so we changed its usage to the recommended version:ruamel.yaml.YAML().dump#577
0.21.0 (2023-10-20)
New features since last release
Changed gate settings serialization so that fields with None values are not in the resulting dictionary #562
Update qiboconnection to 0.12.0 #559
Added phase correction for CZ gates to the optimize step of translate circuit in
qililab.transpiler.transpiler. Gates now can accept an optional dicionary with additional settings. As an example, the CZ phase correction can be added at options for each qubit:CZ(0,2): - bus: flux_line_q2_bus pulse: amplitude: 1.0 phase: 0 duration: 101 shape: name: snz t_phi: 1 b: 0.5 options: q0_phase_correction: 0.1 q2_phase_correction: 0.2The default value for the
optimizeflag in qililab.transpiler.transpiler.translate_circuit has been changed fromFalsetoTruebuild_platform() has been extended: #533
Now appart from passing the runcard YAML file path, you can directly pass an already build dictionary.
Also the argument has changed names from
pathtoruncard.Buses serialization have been implemented: #515
When printing the runcard, in the buses part we will now have the normal Buses serialization, plus the parameters of the instruments associated to that bus, with the
to_dict/from_dictmethods.`Also the serialization includes using the
set/get_paramsfor setting/getting the instruments params.Distorsions and PulseShapes have been improved: #512
They now work for
amplitude=0, and for negative andsnzenvelopes (both positive and negatives)It now also adds the
norm_factorparameter for manual normalization to all the distortions (previously only in the lfilter distortion)And finally we also have added the option to skip the automatic normalization that we do, setting the parameter
auto_normtoFalse, (defaults toTrue).Plus, added a lots of tests and documentation to both classes.
Fixed bug which did not allow gaussian waveforms to have amplitude 0 #471
Delete
Schemaclass fromPlatformandRuncardSchemaclasses (and from the rest of qililab).Also
RuncardSchemais now called simplyRuncard(since its the class that maps our runcard files).This PR brings importants simplifications to the full qililab structure, now the runcard will have the following structure:
name: ... device_id: ... gates_settings: # Old `settings` without name & device_id ... chip: ... buses: ... instruments: ... instrument_controllers: ...instead than the previous:
settings: name: ... device_id: ... ... schema: # Schema disappears from the platform. chip: ... buses: ... instruments: ... instrument_controllers: ...Notice also how
settings(and his respective classPlatformSettings) has changed togates_settings(and the class toGatesSettingshaving the runcard string and the class the same name now, before they didn’t).Simplify circuit gate to pulse transpilation. Previous hardware gates are removed. Now gates can be defined in the runcard as a list of
GateEventitems with bus, wait time (optional) and pulse information. This allows more customization and freedom of what a certain gate does. The gate will be transpiled as long as the circuit gate’s name and qubits match those of the gate in the runcard. An example of a custom gate for the circuit X gate at qubit 0 and a CZ gate at (0,1)X(0): - bus: drive_line_q0_bus # alias of the bus wait_time: 200 pulse: amplitude: 0.5 phase: 0 duration: 200 frequency: 0 shape: name: drag drag_coefficient: 1 num_sigmas: 2 - bus: flux_line_q0_bus # alias of the bus pulse: amplitude: 1.0 phase: 0 duration: 200 frequency: 0 shape: name: rectangular CZ(0,1): - bus: flux_line_q0_bus # park pulse pulse: amplitude: 0.5 phase: 0 duration: 241 frequency: 0 shape: name: rectangular - bus: flux_line_q1_bus # snz wait_time: 40 # wait 40ns after start of the park pulse pulse: amplitude: 1 phase: 0 duration: 201 frequency: 0 shape: name: snz b: 0.5 t_phi: 1Experiments can access
GateEventitems by using the gate and qubitaliaslike previously and adding_itemto access aGateEventthat is not the first event of the gate. For example,set_parameter(parameter='amplitude', value=0.8, alias='X(0)')will set the amplitude in the gate setting above from 0.5 to 0.8. This is equivalent toalias='X(0)_0'. Howeveralias='X(0)_1'sets instead the amplitude of the second event (bus=flux_line_q0_bus) from 1.0 to 0.8 #472Rename Experiment and CircuitExperiment classes and dependencies: This branch renames the Experiment class to BaseExperiment and CircuitExperiment to Experiment. #482
Add a new Factory for the Buses and registered the current ones #487
Add the NEW_DRIVERS flag to choose between old and new instruments and bus drivers. #486
Add a new Factory for the InstrumentDrivers and registered the current ones #473
Add interfaces and drivers for Flux bus: This PR brings the qililab implementation of the Flux bus driver and unittests. #469
Add ReadoutBus class. #465
Fix: check whether cluster has submodules not present at init time. #477
Add interfaces and drivers for Voltage and Current sources: This PR brings the qililab implementation of the Keithly2600 and Yokowaga QCodes drivers and unittests. #438
Fix: add acquisitions and weights to Sequencer QRM #461
Add DriveBus and its interface for the new bus structure. 457
Add QProgram for developing quantum programs in the bus level, the operations
Play,Sync,Wait,Acquire,SetGain,SetOffset,SetFrequency,SetPhase,ResetPhase, and the iteration blocksAcquireLoopandLoop. 452Add QBloxCompiler for compiling QProgram into QPySequence. 481
Add waveforms for the new QProgram 456
Add interface for Voltage and Current sources #448
New AWG Interface + SequencerQCM, Pulsar, QCM-QRM drivers #442
New Digitiser interface + SequencerQRM driver #443
Add interface for the Attenuator. This is part of the “Promoting Modular Autonomy” epic. #432
Added new drivers for Local Oscillators inheriting from QCoDeS drivers and Local Oscillator interface. This is part of the “Promoting Modular Autonomy” epic. #437
Add qcodes_contrib_drivers (0.18.0) to requierements #440
Update qcodes to latest current version (0.38.1) #431
Added hotfix for bus delay issue from Hardware: This fix adds a delay for each pulse on a bus #439
Added
T1portfolio experiment #409The
ExecutionManagercan now be built from the loops of the experiment. This is done byaliasmatching, the loops will be executed on the bus with the samealias. Note that aliases are not unique, therefore the execution builder will use the first bus alias that matches the loop alias. An exception is raised if aloop.aliasdoes not match anybus.aliasspecified in the runcard #320Added
T2Echoportfolio experiment #415The
ExecutionManagercan now be built from the loops of the experiment. This is done byaliasmatching, the loops will be executed on the bus with the samealias. Note that aliases are not unique, therefore the execution builder will use the first bus alias that matches the loop alias. An exception is raised if aloop.aliasdoes not match anybus.aliasspecified in the runcard #320The
Experimentclass has been changed to support a more general definition of experiment by removing thecircuitsandpulse_schedules. A new classCircuitExperimentinherits from the newExperimentclass has the previous attributes and all the functionality the oldExperimenthad.experiment = Experiment(platform=platform, options=options) experiment_2 = CircuitExperiment(platform=platform, options=options, circuits=[circuit])Added
threshold_rotationparameter toAWGADCSequencer. This adds a new parameter to the runcard of sequencers of that type, QRM sequencers in the case of Qblox. This value is an angle expressed in degrees from 0.0 to 360.0.awg_sequencers: - identifier: 0 chip_port_id: 1 intermediate_frequency: 1.e+08 weights_path0: [0.98, ...] weights_path1: [0.72, ...] weighed_acq_enabled: true threshold: 0.5 threshold_rotation: 45.0 # <-- new line
Improvements
Add
ForLoopiteration method to QProgram. 481Add
Parallelblock to QProgram to allow parallel loops, and compilation support to QBloxCompiler. 496Allow CZ gates to use different pulse shapes #406
Add support for the
WaitgateAddeds support for the
Waitgate #405Added support for
Parameter.Gate_Parameterinexperiment.set_parameter()method. In this case, alias is a, convertable to integer, string that denotes the index of the parameter to change, as returned bycircuit.get_parameters()method. #404The
Chipclass now uses thealiasof each node to define node connections. #494Before:
chip: nodes: - name: qubit alias: qubit_0 id_: 0 qubit_index: 0 frequency: 4.92e+09 nodes: [2, 10, 20, 30]Now:
chip: nodes: - name: qubit alias: qubit_0 qubit_index: 0 frequency: 4.92e+09 nodes: [qubit_2, resonator_q0, drive_line_q0, flux_line_q0]ql.executenow accepts a list of circuits! #549
Breaking changes
Old scripts using
Experimentwith circuits should be changed and useCircuitExperimentinstead. #334
Deprecations / Removals
idandcategoryattributes have been removed fromqililab. #494
Documentation
Documentation for the Chip module: [#553] (https://github.com/qilimanjaro-tech/qililab/pull/553)
Includes documentation for all public features of the Chip module
Documentation for the Pulse module: #532
Includes documentation for all public features of the Pulse module
Added documentation for platform module and the tutorial sections of Platform and Runcards: #531
Bug fixes
Avoid creating empty sequences for buses that are no flux lines and do for flux ones that do not have any AWG instrument. #556
The
thresholdandthreshold_rotationparameters of aQbloxQRMcan now be set usingPlatform.set_parameter. #534The
QbloxQRMRFandQbloxQCMRFdo not save an empty list for the parameterout_offsetsin the saved runcard. #565The
save_platformnow saves in the yaml file float values with the same precision as in thePlatformobject. #565
0.20.0 (2023-05-26)
New features since last release
Added hotfixes for several issues encountered during the hackathon: #413
Save experiments flag for experiments execute method
# Option 1 (Default, save_experiment=True) experiment = Experiment(platform=platform, circuits=circuits, options=options) experiment.execute() # Option 2 (Equivalent to option 1, save_experiment=False) experiment = Experiment(platform=platform, circuits=circuits, options=options) experiment.execute(save_experiment=False)Empty sequences to avoid creating repeated programs.
Create empty programs for all qubit flux lines to activate calibrated offsets.
Added method to get qubits from the chip
qubits = ql.Chip.qubits()Added to the
draw()method the option of specifying if you want:modulation or not,
plot the real, iamginary, absolute or any combination of these options
specify the type of plotline to use, such as “-”, “.”, “–”, “:”… for the classes
ExperimentalandExecutionManager, like:
# Option 1 (Default) figure = sample_experiment.draw(real=True, imag=True, abs=False, modulation=True, linestyle="-") # Option 2 (Equivalent to option 1) figure = sample_experiment.draw() # Option 3 (something different, only plotting the envelopes without modulation) figure = sample_experiment.draw(modulation=False, linestyle=".") plt.show()Added
lambda_2attribute to thecosine.pymodule containing theCosinepulse_shape, modifying the previous A/2*(1-cos(x)). Into a more general A/2*(1-lambda_1*cos(phi)-lambda_2*cos(2phi)), giving a modified sinusoidal-gaussian.lambda_1 cosine A/2*(1-cos(x)): Starts at height 0 (phase=0), maximum height A (phase=pi) and ends at height 0 (phase=2pi). Which is a sinusoidal like gaussian.
lambda_2 cosine A/2*(1-cos(2x)): Starts at height 0 (phase=0), maximum height A (phase=pi/2) then another height 0 in the middle at phase=pi, then another maximum height A (phase=3/2pi) and ends at height 0 (phase=2pi).
For more info check the docstring and the following references:
Supplemental material B. “Flux pulse parametrization” at [https://arxiv.org/abs/1903.02492%5C%5D],
OPTIMAL SOLUTION: SMALL CHANGE IN θ at [https://arxiv.org/abs/1402.5467%5C%5D]
Added user integration for
pulse_distortions. Now they can be used writing them in the Buses of the runcards:buses: - id_: 0 category: bus alias: feedline_bus system_control: id_: 0 name: readout_system_control category: system_control instruments: [QRM1, rs_1] port: 100 distortions: # <-- new line - name: bias_tee # <-- new line tau_bias_tee: 1.0 # <-- new line - name: lfilter # <-- new line a: [0.1, 1.1] # <-- new line b: [1.1, 1.3] # <-- new line - id_: 10 category: bus alias: drive_line_q0_bus system_control: id_: 10 name: system_control category: system_control instruments: [QCM-RF1] port: 10 distortions: [] # <-- new lineAdded CZ gate support, 2 qubit gate support to
circuit_to_pulseand corresponding definitions to the runcard.CZ implements a Sudden Net Zero (SNZ) pulse through the flux line as well as a parking gate (if defined in the runcard) to adjacent qubits with lower frequency than CZ’s target qubit. For the parking gate, if the time is greater than the CZ pulse, the extra time is added as padding at the beginning/end of the pulse. The parameters for the CZ in the runcard are amplitude, duration of the halfpulse; and for the CZ’s snz pulse b (impulse between halfpulses) and t_phi (time between halfpulses without accounting for b)
Example:
gates: 1: - name: Park amplitude: 1.0 phase: 0 duration: 103 shape: name: rectangular (0,2): - name: CZ amplitude: 1.0 phase: duration: 40 shape: name: snz b: 0.5 t_phi: 1In the example above, if qubit 1 is connected to 2 and has lower frequency, there will be an attempt to apply a parking pulse. If a Park gate definition is found for qubit 1, then a parking pulse will be applied. The total duration of the CZ gate above will be 2*duration + t_phi + 2 = 83 (each b has 1ns duration and there are 2 bs). Thus the parking gate lasts for some extra 20ns which will result in 10ns ‘pad time’ in the parking gate before and after the SNZ pulse. Note that the order of the qubits in the CZ is important even if the gate is symmetric, because the second qubit will be the target for the SNZ pulse. #369
Added
cosine.pymodule containing aCosinechild class ofpulse_shape, which gives a sinusoidal like gaussian A/2*(1-cos(x)). The shape starts at height 0 (phase=0), maximum height A (phase=pi) and ends at height 0 (phase=2pi)pulse = Pulse( amplitude=..., phase=..., duration=..., frequency=..., pulse_shape=Cosine(), )Added
pulse.pulse_distortion.lfilter_correction.pymodule, which is another child class for thepulse.pulse_distortionpackage.distorted_envelope = LFilter(norm_factor=1.2, a=[0.7, 1.3], b=[0.5, 0.6]).apply(original_envelopes)Also adds a phase property to
PulseEventand implementsFactory.getdirectly in thefrom_dict()method of the parent classPulseDistortion.Added
get_port_from_qubit_idxmethod toChipclass. This method takes the qubit index and the line type as arguments and returns the associated port. #362Added
pulse.pulse_distortionpackage, which contains a modulepulse_distortion.pywith the base class to distort envelopes inPulseEvent, and two modulesbias_tee_correction.pyandexponential_decay_correction.py, each containing examples of distortion child classes to apply. This new feature can be used in two ways, directly from the class itself:distorted_envelope = BiasTeeCorrection(tau_bias_tee=1.0).apply(original_envelope)or from the class PulseEvent (which ends up calling the previous one):
pulse_event = PulseEvent( pulse="example_pulse", start_time="example_start", distortions=[ BiasTeeCorrection(tau_bias_tee=1.0), BiasTeeCorrection(tau_bias_tee=0.8), ], ) distorted_envelope = pulse_event.envelope()This would apply them like: BiasTeeCorrection_0.8(BiasTeeCorrection_1.0(original_pulse)), so the first one gets applied first and so on… (If you write their composition, it will be in reverse order respect the list)
Also along the way modified/refactored the to_dict() and from_dict() and envelope() methods of PulseEvent, Pulse, PulseShape… since they had some bugs, such as:
the dict() methods edited the external dictionaries making them unusable two times.
the maximum of the envelopes didn’t correspond to the given amplitude.
The
QbloxQCMRFmodule has been added. To use it, please use theQCM-RFname inside the runcard:- name: QCM-RF alias: QCM-RF0 id_: 2 category: awg firmware: 0.7.0 num_sequencers: 1 out0_lo_freq: 3700000000 # <-- new line out0_lo_en: true # <-- new line out0_att: 10 # <-- new line out0_offset_path0: 0.2 # <-- new line out0_offset_path1: 0.07 # <-- new line out1_lo_freq: 3900000000 # <-- new line out1_lo_en: true # <-- new line out1_att: 6 # <-- new line out1_offset_path0: 0.1 # <-- new line out1_offset_path1: 0.6 # <-- new line awg_sequencers: ...The
QbloxQRMRFmodule has been added. To use it, please use theQRM-RFname inside the runcard:- name: QRM-RF alias: QRM-RF0 id_: 0 category: awg firmware: 0.7.0 num_sequencers: 1 out0_in0_lo_freq: 3000000000 # <-- new line out0_in0_lo_en: true # <-- new line out0_att: 34 # <-- new line in0_att: 28 # <-- new line out0_offset_path0: 0.123 # <-- new line out0_offset_path1: 1.234 # <-- new line acquisition_delay_time: 100 awg_sequencers: ...
Improvements
The
get_bus_by_qubit_indexmethod ofPlatformclass now returns a tuple of three buses:flux_bus, control_bux, readout_bus. #362Arbitrary mapping of I/Q channels to outputs is now possible with the Qblox driver. When using a mapping that is not possible in hardware, the waveforms of the corresponding paths are swapped (in software) to allow it. For example, when loading a runcard with the following sequencer mapping a warning should be raised:
awg_sequencers: - identifier: 0 output_i: 1 output_q: 0>>> platform = build_platform(name=runcard_name) [qililab] [0.16.1|WARNING|2023-05-09 17:18:51]: Cannot set `output_i=1` and `output_q=0` in hardware. The I/Q signals sent to sequencer 0 will be swapped to allow this setting.Under the hood, the driver maps
path0 -> output0andpath1 -> output1. When applying an I/Q pulse, it sends the I signal throughpath1and the Q signal throughpath0. #324The versions of the
qblox-instrumentsandqpysequencerequirements have been updated to0.9.0#337Allow uploading negative envelopes on the
QbloxModuleclass. #356The parameter
sync_enof the Qblox sequencers is now updated automatically when uploading a program to a sequencer. This parameter can no longer be set usingset_parameter. #353The Qblox RF modules now support setting their LO frequency using the generic
Parameter.LO_FREQUENCYparameter. #455
Deprecations / Removals
Bug fixes
Add
_set_markersmethod to theQbloxModuleclass and enable all markers. For the RF modules, this command enables the outputs/inputs of the instrument. We decided to enable all markers by default to be able to use them later if needed. #361
0.19.0 (2023-05-08)
New features since last release
Added Drag gate support to
circuit_to_pulseso that Drag gates are implemented as drag pulses #312Added
experiment/portfolio/submodule, which will contain pre-defined experiments and their analysis. #189Added
ExperimentAnalysisclass, which contains methods used to analyze the results of an experiment. #189Added
Rabiportfolio experiment. Here is a usage example:loop_range = np.linspace(start=0, stop=1, step=0.1) rabi = Rabi(platform=platform, qubit=0, range=loop_range) rabi.turn_on_instruments() bus_parameters = {Parameter.GAIN: 0.8, Parameter.FREQUENCY: 5e9} rabi.bus_setup(bus_parameters, control=True) # set parameters of control bus x_parameters = {Parameter.DURATION: 40} rabi.gate_setup(x_parameters, gate="X") # set parameters of X gate rabi.build_execution() results = rabi.run() # all the returned values are also saved inside the `Rabi` class! post_processed_results = rabi.post_process_results() fitted_parameters = rabi.fit() fig = rabi.plot()Added
FlippingSequenceportfolio experiment. #245Added
get_bus_by_qubit_indexmethod to thePlatformclass. #189Added
circuitmodule, which contains everything related to Qililab’s internal circuit representation.The module contains the following submodules:
circuit/converters: Contains classes that can convert from external circuit representation to Qililab’s internal circuit representation and vice versa.circuit/nodes: Contains classes representing graph nodes that are used in circuit’s internal graph data structure.circuit/operations: Contains classes representing operations that can be added to the circuit. #175
Added
Circuitclass for representing quantum circuits. The class stores the quantum circuit as a directed acyclic graph (DAG) using therustworkxlibrary for manipulation. It offers methods to add operations to the circuit, calculate the circuit’s depth, and visualize the circuit. Example usage:# create a Circuit with two qubits circuit = Circuit(2) # add operations for qubit in [0, 1]: circuit.add(qubit, X()) circuit.add(0, Wait(t=100)) circuit.add(0, X()) circuit.add((0, 1), Measure()) # print depth of circuit print(f"Depth: {circuit.depth}") # print circuit circuit.print() # draw circuit's graph circuit.draw()Added
OperationFactoryclass to register and retrieve operation classes based on their names. #175Added
CircuitTranspilerclass for calculating operation timings and transpiling quantum circuits into pulse operations. Thecalculate_timings()method annotates operations in the circuit with timing information by evaluating start and end times for each operation. Theremove_special_operations()method removes special operations (Barrier, Wait, Passive Reset) from the circuit after the timings have been calculated. Thetranspile_to_pulse_operations()method then transpiles the quantum circuit operations into pulse operations, taking into account the calculated timings. Example usage:# create the transpiler transpiler = CircuitTranspiler(settings=platform.settings) # calculate timings circuit_ir1 = transpiler.calculate_timings(circuit) # remove special operations circuit_ir2 = transpiler.remove_special_operations(circuit_ir1) # transpile operations to pulse operations circuit_ir3 = transpiler.transpile_to_pulse_operations(circuit_ir2)Added
QiliQasmConverterclass to convert a circuit from/to QiliQASM, an over-simplified QASM version. Example usage:# Convert to QiliQASM qasm = QiliQasmConverter.to_qasm(circuit) print(qasm) # Parse from QiliQASM parsed_circuit = QiliQasmConverter.from_qasm(qasm)Pulses with different frequencies will be automatically sent and read by different sequencers (multiplexed readout). #242
Added an optional parameter “frequency” to the “modulated_waveforms” method of the Pulse and PulseEvent classes, allowing for specification of a modulation frequency different from that of the Pulse. #242
Added
valuesandchannel_idattribute to theLoopclass. Here is an example on how a loop is created now:new_loop = Loop(alias="loop", parameter=Parameter.POWER, values=np.linspace(1, 10, 10))Gate settings can be set for each qubit individually, or tuple of qubits in case of two-qubit gates. Example of updated runcard schema:
gates: 0: - name: M amplitude: 1.0 phase: 0 duration: 6000 shape: name: rectangular - name: X amplitude: 1.0 phase: 0 duration: 100 shape: name: gaussian num_sigmas: 4 1: - name: M amplitude: 1.0 phase: 0 duration: 6000 shape: name: rectangular - name: X amplitude: 1.0 phase: 0 duration: 100 shape: name: gaussian num_sigmas: 4 (0,1): - name: CPhase amplitude: 1.0 phase: 0 duration: 6000 shape: name: rectangularTo change settings with set_parameter methods, use the alias format “GATE(QUBITs)”. For example:
platform.set_parameter(alias="X(0)", parameter=Parameter.DURATION, value=40) platform.set_parameter(alias="CPhase(0,1)", parameter=Parameter.DURATION, value=80)Weighted acquisition is supported. The weight arrays are set as sequencer parameters
weights_iandweights_q, and the weighed acquisition can be enabled setting the sequencer parameterweighed_acq_enabledtotrue. Note: theintegration_lengthparameter will be ignored ifweighed_acq_enabledis set totrue, and the length of the weights arrays will be used instead.
awg_sequencers:
- identifier: 0
chip_port_id: 1
intermediate_frequency: 1.e+08
weights_i: [0.98, ...] # <-- new line
weights_q: [0.72, ...] # <-- new line
weighed_acq_enabled: true # <-- new line
threshold: 0.5 # <-- new line
Result,ResultsandAcquisitionsclasses implement thecountsmethod, which returns a dictionary-like object containing the counts of each measurement based in the discretization of the instrument via thethresholdsequencer parameter. Alternatively, theprobabilitiesmethod can also be used, which returns a normalized version of the same counts object.>>> counts = result.counts() Counts: {'00': 502, '01': 23, '10': 19, '11': 480} >>> probabilities = result.probabilities() Probabilities: {'00': 0.49023438, '01': 0.02246094, '10': 0.01855469, '11': 0.46875}
Improvements
Return an integer (instead of the
Portclass) when callingChip.get_port. This is to avoid using the privateid_attribute of thePortclass to obtain the port index. #189The asynchronous data handling used to save results and send data to the live plotting has been improved. Now we are saving the results in a queue, and there is only ONE thread which retrieves the results from the queue, sends them to the live plotting and saves them to a file. #282
The asynchronous data handling used to save results and send data to the live plotting has been improved. Previously we only had ONE active thread retrieving the results and saving them but was created and killed after processing one result of the total
Resultsobject. Now we are creating the thread just ONCE, so threading is handled at theExperimentlevel instead of what was done previously at theExution_Managerlevel. #298
Breaking changes
draw()method ofCircuituses Graphviz internally. To be able to call the method Graphviz must be installed. In Ubuntu-based distros a simplesudo apt-get install graphvizis sufficient. For detailed installation information for your OS please consult Graphviz’s installation page. #175gatesproperty of runcard must be updated to provide a list of gate settings for each qubit individually. #292
Deprecations / Removals
The
Executionclass has been removed. Its functionality is now added to theExecutionManagerclass. Please useExecutionManager``instead. The ``ExecutionBuilderreturns now an instance ofExecutionManager. #246The
LoopOptionsclass has been removed. It was used to create a numpy array and store this array in thevaluesattribute which is now in theLoopclass. #254The
plot_y_labelargument of theExperimentOptionsclass has been removed. #282All the
probabilitiesmethods that returned apandas.DataFramereturn now adict[str, float]. All the methods related to the construction of such dataframes have been removed. #283
Documentation
Bug fixes
0.18.0 (2023-04-11)
New features since last release
Added
Experiment.compilemethod, which return the compiled experiment for debugging purposes. #225>>> sequences = experiment.compile()This method returns a list of dictionaries (one dictionary per circuit executed in the experiment). Each dictionary contains the sequences uploaded for each bus:
>>> sequences[0] {'drive_line_bus': [qpysequence_1], 'feedline_input_output_bus': [qpysequence_2]}This experiment is using two buses (
drive_line_busandfeedling_input_output_bus), which have a list of the uploaded sequences (in this case only 1).We can then obtain the program of such sequences:
>>> sequences[0]["drive_line_bus"][0]._program setup: move 1000, R0 wait_sync 4 average: reset_ph play 0, 1, 4 long_wait_1: move 3, R1 long_wait_1_loop: wait 65532 loop R1, @long_wait_1_loop wait 3400 loop R0, @average stop: stopAdded support for setting output offsets of a qblox module. #199
Added gate to native gate transpiler. Contains method
translate_circuitwhich translates a qibo.Circuit to a qibo.Circuit with native gates (Drag pulses, C-phase), virtual Zs and measurement gates only. #244Added optimizer for the native gate transpiler. Shifts all Z, RZ gates to the left and removes them before measurement. #269
Improvements
Added support for the execution of pulses with durations that are not multiples of 4. For this, a new
minimum_clock_timeattribute has been added to the runcard:settings: id_: 0 category: platform name: spectro_v_flux device_id: 9 minimum_clock_time: 4 # <-- new line!When a pulse has a duration that is not a multiple of the
minimum_clock_time, a padding of 0s is added after the pulse to make sure the next pulse falls within a multiple of 4. #227Change name
PulseScheduledBustoBusExecution. #225Separate
generate_program_and_uploadinto two methods:compileandupload. From now on, when executing a single circuit, all the pulses of each bus will be compiled first, and then uploaded to the instruments. #225Make
nshotsandrepetition_durationdynamic attributes of theQbloxModuleclass. When any of these two settings changes, the cache is emptied to make sure new programs are compiled. #225Added methods to
PulseBusSchedulefor multiplexing: #236frequencies()returns a list of the frequencies in the schedule.with_frequency(frequency: float)returns a newPulseBusSchedulecontaining only those events at that frequency.
Pulse,PulseEvent,PulseShapesand child classes are now immutable. #236
Breaking changes
An
out_offsetsattribute has been added to the settings of aQbloxModuleobject. This attribute contains a list of the offsets applied to each output. The runcard should be updated to contain this new information:instruments: - name: QRM alias: QRM id_: 1 category: awg firmware: 0.7.0 num_sequencers: 1 acquisition_delay_time: 100 out_offsets: [0.3, 0, 0, 0] # <-- this new line needs to be added to the runcard! awg_sequencers: ...
Deprecations / Removals
Bug fixes
0.17.0 (2023-03-27)
New features since last release
Improvements
Cast
chipdictionary into theChipSchemaclass and remove unusedInstrumentControllerSchemaclass. #187Upload sequence directly to Qblox instruments, without having to save & load a
jsonfile. #197Changed
schedule_index_to_loadargument toidxfor more readability. #192Refactored the
Experimentclass, creating a method for each step of the workflow. TheExperiment.executemethod will run all these methods in order: #192connect: Connect to the instruments and block the device.initial_setup: Apply runcard settings to the instruments.build_execution:Translate the circuit into pulses.
Create the
Executionclass (which contains all the buses with the pulses to execute).Initialize the live plotting.
Create the
Resultsclass and theresults.ymlfile (where the results will be stored).
turn_on_instruments: Turn on the instruments (if necessary).run: Iterate over all the loop values, and for each step:
Generate the program.
Upload the program.
Execute the program.
Save the result to the
results.ymlfile.Send data to live plotting.
Save the result to the
Experiment.resultsattribute.
turn_off_instruments: Turn off the instruments (if necessary).disconnect: Disconnect from the platform and release the device.remote_save_experiment: Ifremote_save = True, save the experiment and the results to the database.
When translating a Circuit into pulses, the target qubit/resonator frequency is now used to initialize the corresponding pulse. #209
Breaking changes
Removed context manager from
Executionclass. Users will be responsible for turning off and disconnecting the instruments when not using theexecutemethod directly! #192Removed the
ExecutionOptionsclass. Now the user can freely choose which steps of the workflow to execute. #192Removed the
Platform.connect_and_initial_setupmethod. #192Move
connectionanddevice_idinformation into thePlatformclass. Now users should adddevice_idinside the runcard and add aconnectionargument when callingbuild_platform: #211platform = build_platform(name=runcard_name, connection=connection) platform.connect(manual_override=False)Removed the frequency argument from the
Pulse.modulated_waveformsmethod (and all the methods that uses this method internally). Removefrequencyproperty from certain buses. #209The
Pulse.frequencyargument is now mandatory to initialize a pulse. #209
Deprecations / Removals
Removed the
ExecutionPreparationclass and theresults_data_management.pyfile, and replace it with aprepare_resultsmethod inside theExperimentclass. #192Removed unused
connect,disconnectandsetupmethods from theExecutionclass. These are used in theExperimentclass, which call the corresponding methods of thePlatformclass. #192Removed the
RemoteAPIclass. This class didn’t add any functionality. #192Removed all the
BusandSystemControltypes. Now there is only a genericBus, that can contain aSystemControl,ReadoutSystemControl(which contain a list of instruments to control) orSimulatedSystemControl, which is used to control simulated quantum systems. #210
Bug fixes
Fixed wrong timing calculation in Q1ASM generation #186
Fix bug where calling
set_parameterwithParameter.DRAG_COEFFICIENTwould raise an error. #187The
qiboversion has been downgraded to0.1.10to allow installation on Mac laptops. #185Fixed the
Platform.get_elementmethod: #192Now calling
get_elementof a gate returns aGateSettingsinstance, instead of aPlatformSettingsinstance.Add try/except over the
chip.get_node_from_aliasmethod to avoid getting an error if the node doesn’t exist.
0.16.1 (2023-02-24)
Fix
Platform should be stateful for connections (#143)
0.16.0 (2023-02-07)
Feat
updates to Qibo v0.1.11, fixes breaking changes (#139)
0.15.1 (2023-01-26)
Fix
Duplicate hardware_average property & bus.run() in parallel error (#136)
0.15.0 (2023-01-24)
Feat
Experimentally validated & debugged Spectroscopy (#134)
0.14.0 (2023-01-17)
Feat
Experiment: added remote experiment saving (#112)
0.13.0 (2023-01-17)
Feat
enums: transform them to string enums (#125)
Fix
remove hardcoded modulation from Pulse (#127)
0.12.0 (2023-01-17)
Feat
Update qblox and qpysequence
0.11.0 (2023-01-12)
Feat
custom exceptions
0.10.3 (2022-12-21)
Fix
Results: fixed no-results dataframe generation (#109)
0.10.2 (2022-12-14)
Refactor
[qili-243] sequence class (#104)
0.10.1 (2022-12-14)
Fix
negative-wait (#106)
0.10.0 (2022-12-13)
Feat
[QILI-201] multibus support (#101)
0.9.2 (2022-11-17)
Fix
remove master drag coefficient (#98)
0.9.1 (2022-11-17)
Refactor
pulse events (#93)
0.9.0 (2022-10-06)
Feat
qilisimulator integration (#79)
0.8.0 (2022-10-05)
Feat
qilisimulator integration (#77)
0.7.3 (2022-10-03)
Fix
[QILI-169] load 2D results (#69)
0.7.2 (2022-08-22)
Fix
[QILI-187 ] :bug: loops minimum length taking the passed value instead of the self (#57)
0.7.1 (2022-08-19)
Refactor
[QILI-186] :recycle: renamed beta to drag_coefficient (#56)
0.7.0 (2022-08-19)
Feat
[QILI-185] add option to NOT reset an instrument (#54)
0.6.0 (2022-08-18)
Feat
[QILI-184] :sparkles: New daily directory generated for results data (#50)
0.5.9 (2022-08-18)
Fix
[QILI-183] :bug: accept float master duration gate (#49)
0.5.8 (2022-08-18)
Fix
[QILI-182] :bug: uses deepcopy before pop dict key (#48)
0.5.7 (2022-08-17)
Fix
set beta serialization correctly (#47)
0.5.6 (2022-08-17)
Fix
reference clock after reset and using only the necessary sequencers
0.5.5 (2022-07-27)
Fix
setup: versioning
0.5.4 (2022-07-26)
Fix
[QILI-181] :bug: fixed values types when they are numpy (#38)
0.5.3 (2022-07-26)
Fix
[QILI-178] set beta master (#37)
0.5.2 (2022-07-26)
Fix
[QILI-180] :bug: check for multiple loops correctly (#36)
0.5.1 (2022-07-25)
Fix
[QILI-177] :bug: make sure amplitude and duration are float or int (#35)
0.5.0 (2022-07-24)
Feat
[QILI-174] loop support multiple parameters (#34)
0.4.2 (2022-07-23)
Fix
[QILI-176] set master value for gate amplitude and duration (#33)
0.4.1 (2022-07-23)
Fix
[QILI-168] Set voltage normalization (#32)
0.4.0 (2022-07-20)
Feat
New features from TII trip (#31)
0.3.0 (2022-04-26)
Feat
[QILI-81] Implement schema class (#5)
0.2.0 (2022-04-19)
Feat
[QILI-46] Implement instrument classes (#9)
0.1.0 (2022-04-06)
Feat
[QILI-48] Implement platform, backend and settings classes (#8)