0.19.0
New features since last release
-
Added
experiment/portfolio/
submodule, which will contain pre-defined experiments and their analysis.
#189 -
Added
ExperimentAnalysis
class, which contains methods used to analyze the results of an experiment.
#189 -
Added
Rabi
portfolio 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
FlippingSequence
portfolio experiment.
#245 -
Added
get_bus_by_qubit_index
method to thePlatform
class.
#189 -
Added
circuit
module, 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
Circuit
class for representing quantum circuits. The class stores the quantum circuit as a directed acyclic graph (DAG) using therustworkx
library 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
OperationFactory
class to register and retrieve operation classes based on their names.
#175 -
Added
CircuitTranspiler
class 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
QiliQasmConverter
class 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
values
andchannel_id
attribute to theLoop
class.
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: rectangular
To 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_path0
andweights_path1
, and the weighed acquisition can be enabled setting the sequencer parameterweighed_acq_enabled
totrue
. Note: theintegration_length
parameter will be ignored ifweighed_acq_enabled
is 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_path0: [0.98, ...] # <-- new line weights_path1: [0.72, ...] # <-- new line weighed_acq_enabled: true # <-- new line threshold: 0.5 # <-- new line
-
Result
,Results
andAcquisitions
classes implement thecounts
method, which returns a dictionary-like object containing the counts of each measurement based in the discretization of the instrument via thethreshold
sequencer parameter. Alternatively, theprobabilities
method 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
Port
class) when callingChip.get_port
. This is to avoid using the private
id_
attribute of thePort
class to obtain the port index.
#189 -
The 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 totalResults
object. Now we are creating the thread just ONCE, so threading is handled at theExperiment
level instead of what was done previously at theExution_Manager
level.
#298
Breaking changes
-
draw()
method ofCircuit
uses Graphviz internally. To be able to call the method Graphviz must be installed. In Ubuntu-based distros a simplesudo apt-get install graphviz
is sufficient. For detailed installation information for your OS please consult Graphviz's installation page.
#175 -
gates
property of runcard must be updated to provide a list of gate settings for each qubit individually.
#292
Deprecations / Removals
-
The
Execution
class has been removed. Its functionality is now added to theExecutionManager
class.
Please useExecutionManager
instead. TheExecutionBuilder
returns now an instance ofExecutionManager
.
#246 -
The
LoopOptions
class has been removed. It was used to create a numpy array and store this array in thevalues
attribute which is now in theLoop
class.
#254 -
The
plot_y_label
argument of theExperimentOptions
class has been removed.
#282 -
All the
probabilities
methods that returned apandas.DataFrame
return now adict[str, float]
. All the methods related to the construction of such dataframes have been removed.
#283