Package: qiclib
qiclib Python packageqiclib is Quantum Interface's official Python client for the QiController.The QiController is currently developed at theInstitute for Data Processing and ElectronicsfromKarlsruhe Institute of Technology (KIT).InstallingTo install the Python package and make it available globally usingimport qiclib, use:$pipinstallqiclibDevelopingIf you want to be able to make local changes to the source code without the necessity to re-install, please clone the repository locally and install it in editable mode:$pipinstall-e.NOTE: If you add/remove files in this mode, you will still have to re-run this command.In order to be able to commit and push changes, you will have to furthermore install the dev dependencies:$pipinstall-rrequirements-dev.txtand then install thepre-commithook before committing:$pre-commitinstallGetting StartedThe QiController needs to be powered and connected to the same network as the control computer. It can then be accessed via its IP address or host name.Everything is based on the QiController driver class, so simply import qiclib and establish a connection:importqiclibasqlfromqiclib.codeimport*qic=ql.QiController('IP ADDRESS OR HOST NAME')qiclib includes a high-level description language called QiCode (already imported using the second line above). With it, you can conveniently specify your experiments in an easy and intuitive manner.QiCode lets you specify experiments in a generic way, so-called QiJobs, and then execute them on your superconducting qubit chip.
The physical properties of your sample are stored inside aQiSampleobject.
The sample can consist of one or more cells.
Each cell corresponds to a qubit and defines all relevant properties for this qubit.
This can be pulse lengths, frequencies, but also other experiment-related parameters.For this introduction, we will stick with one qubit and thus one cell:sample=QiSample(1)# 1 cell/qubit onlysample[0]["rec_pulse"]=416e-9# s readout pulse lengthsample[0]["rec_length"]=400e-9# s recording window sizesample[0]["rec_frequency"]=60e6# Hz readout pulse frequencysample[0]["manip_frequency"]=80e6# Hz control pulse frequencyOne can define as many properties as one likes.
The naming convention of these properties is left completely up to you.
However, if you want to use pre-built experiments from qiclib, you should use the same property names as are used there.
You can also store qubit-related characteristics, like decay times and further information which are not needed for the experiments.
As the sample can be exported as JSON file and imported again later, this can become quite useful.In the sample, we already provided some information on how our readout pulse should look like and how long our recording window should be.
At the beginning, one now typically wants to calibrate the electrical delay of the readout pulse through the experimental setup.
qiclib offers an automated scheme for this purpose, optimizing for the highest signal amplitude at the IF frequency.
Of course, manual calibration (see other methods insideql.init) is also possible.ql.init.calibrate_readout(qic,sample,averages=1000)This will perform multiple experiments on the QiController to determine the electrical delay and to record the final readout window.
It will also plot you the resulting data using matplotlib.
The optimal delay will be stored as"rec_offset"inside the sample object so it can be used for the following experiments.Congratulation! You have successfully put the QiController into operation. Now you can continue reading how to use QiCode for your custom experiments.QiCode UsageThe basic commands and classes that are provided for building your experiments with QiCode are:QiPulse(length, shape, amplitude, phase)Creates a pulse object that can be used in other commandsPlay(cell, pulse)Play the givenpulseat the manipulation output for the givencellPlayReadout(cell, pulse)Same asPlaybut for the readout pulse outputRecording(cell, duration, offset, save_to, state_to)Performs a recording at the input of the cell of givendurationandoffset(electrical delay). Typically used directly after aPlayReadoutcommand. Withsave_to, the result data can be stored and labeled by the given string. Withstate_to, the obtained state can be saved to a QiVariable.Wait(cell, delay)Waits the givendelayin the execution time of thecellbefore continuing with the next command.QiVariable(type),QiTimeVariable()andQiStateVariable()Creates a variable that can be used during the control flow or to temporarily store a measured qubit state.Furthermore, there are context managers (which are used with thewithstatement) to represent control logic:with If(condition):Conditional branching, only executes the indented block that follows if the condition is true.with Else():Can follow afterwith Ifand does exactly what you would expect it to do.with ForRange(variable, start, end, step):The passedvariablewill be looped fromstarttoend(excluded) withstepincrements. The following idented block will be repeated for each value ofvariable.One nice thing about QiCode is that you can define reusable building blocks for your experiments. We call these QiGates and annotate them accordingly (@QiGate). Together with the property names of theQiSample, one can really reuse them for different qubits without any adaptations to the gates:@QiGatedefReadout(cell:QiCell,save_to:str=None):PlayReadout(cell,QiPulse(cell["rec_pulse"],frequency=cell["rec_frequency"]))Recording(cell,duration=cell["rec_length"],offset=cell["rec_offset"],save_to=save_to)@QiGatedefPiPulse(cell:QiCell):Play(cell,QiPulse(cell["pi"],frequency=cell["manip_frequency"]))@QiGatedefThermalize(cell:QiCell):Wait(cell,5*cell["T1"])As with the basic commands, the QiGates typically start by defining the cell on which they act. This is not strictly required though. Furthermore, also multi-qubit gates can be implemented in the same manner acting on multiple cells.Now, one can define a first experiment. In QiCode, experiments are calledQiJoband written in an abstract way so they can be easily reused for different samples. Let us consider a Rabi experiment:# Commands are always encapsulated within the QiJob contextwithQiJob()asrabi:# First, we define how many qubits the experiment requiresq=QiCells(1)# Rabi consists of variable length excitation pulses,# so we need to create a time variablelength=QiTimeVariable()# The variable can then be changed within a for loopwithForRange(length,0,1e-6,20e-9):# Output the manipulation pulse with variable lengthPlay(q[0],QiPulse(length,frequency=q[0]["manip_frequency"]))# Perform a consecutive readout (using the above QiGate)# The data can later by accessed via the specified name "result"Readout(q[0],save_to="result")# Wait for the qubit to thermalize (also a QiGate)Thermalize(q[0])TheQiCellsobject inside theQiJobonly acts as placeholder for the real qubit sample and will be replaced by it once we run the experiment.
The placeholder specifies how many cells/qubits the experiment is written for, so one in this case.
All cell properties that are needed for the Rabi experiment are already defined in oursampleabove where we just calibrated the readout.
So we can just run the job by passing bothQiControllerandQiSampleobject to it:rabi.run(qic,sample,averages=1000)data=rabi.cells[0].data("result")This will execute the whole job including the for loop and repeat and average the whole experiment 1000 times. The resultingdataobject will look like this:[# Averaged I results (len = 50 in this example)np.array([...]),# Averaged Q results (same len)np.array([...])]Job description for the most common experiments are readily available asql.jobs.*functions, likeql.jobs.Rabiorql.jobs.T1.More information on QiCode can be foundhere.Qkit IntegrationThis package is best used together with the quantum measurement suiteQkitwhich has to be installed separately. Stand-alone usage of qiclib with reduced capabilities is also possible.After installation, convenience features like storing sample objects (seeqkit.measure.samples_class) and displaying progress bars within Jupyter(lab) notebooks are available.The following code demonstrates how both packages can be easily combined to perform a Rabi experiment (based on the code above):fromqkit.measure.timedomain.measure_tdimportMeasure_td# We use the rabi QiJob from above and extract an experiment object from itexp=rabi.create_experiment(qic,sample,averages=1000)# Create Qkit measurement object and pass an adapter object as Qkit samplem=Measure_td(exp.qkit_sample)m.set_x_parameters(exp.time_range(0,1e-6,20e-9),'pulse_length',None,'s')m.dirname='rabi'# Start the measurement, and lean back:m.measure_1D_AWG(iterations=1)Everything else is handled for you by Qkit and qiclib! Have fun performing your experiments.TestingTo execute test files use the command:$pytesttests--covContributingIdeas for new features and bug reports are highly welcome. Please use the issue tracker for this purpose.LICENSEqiclib is released under the terms of theGNU General Public Licenseas published by the Free Software Foundation, either version 3 of the License, or any later version.Please see theCOPYINGfiles for details.